public string CreateExpiredJob( InvocationData invocationData, string[] arguments, IDictionary<string, string> parameters, TimeSpan expireIn) { var jobId = Guid.NewGuid().ToString(); // Do not modify the original parameters. var storedParameters = new Dictionary<string, string>(parameters); storedParameters.Add("Type", invocationData.Type); storedParameters.Add("Method", invocationData.Method); storedParameters.Add("ParameterTypes", invocationData.ParameterTypes); storedParameters.Add("Arguments", JobHelper.ToJson(arguments)); storedParameters.Add("CreatedAt", JobHelper.ToStringTimestamp(DateTime.UtcNow)); using (var transaction = _redis.CreateTransaction()) { transaction.QueueCommand(x => x.SetRangeInHash( String.Format(RedisStorage.Prefix + "job:{0}", jobId), storedParameters)); transaction.QueueCommand(x => x.ExpireEntryIn( String.Format(RedisStorage.Prefix + "job:{0}", jobId), expireIn)); // TODO: check return value transaction.Commit(); } return jobId; }
public JobPayload( string id, string queue, InvocationData invocationData) { Id = id; Queue = queue; InvocationData = invocationData; }
public void Deserialize_WrapsAnException_WithTheJobLoadException() { var serializedData = new InvocationData(null, null, null); Assert.Throws<JobLoadException>( () => MethodData.Deserialize(serializedData)); }
public void Deserialize_ThrowsAnException_WhenTypeCanNotBeFound() { var serializedData = new InvocationData( "NonExistingType", "Perform", ""); Assert.Throws<JobLoadException>( () => MethodData.Deserialize(serializedData)); }
public void Deserialize_ThrowsAnException_WhenMethodCanNotBeFound() { var serializedData = new InvocationData( typeof(InvocationDataFacts).AssemblyQualifiedName, "NonExistingMethod", JobHelper.ToJson(new [] { typeof(string) }), ""); Assert.Throws<JobLoadException>( () => serializedData.Deserialize()); }
public void Deserialize_CorrectlyDeserializes_AllTheData() { var type = typeof(TestJob); var methodInfo = type.GetMethod("Perform"); var serializedData = new InvocationData( type.AssemblyQualifiedName, methodInfo.Name, JobHelper.ToJson(new Type[0])); var method = MethodData.Deserialize(serializedData); Assert.Equal(type, method.Type); Assert.Equal(methodInfo, method.MethodInfo); Assert.False(method.OldFormat); }
public string CreateExpiredJob( InvocationData invocationData, string[] arguments, IDictionary<string, string> parameters, TimeSpan expireIn) { if (invocationData == null) throw new ArgumentNullException("invocationData"); if (arguments == null) throw new ArgumentNullException("arguments"); if (parameters == null) throw new ArgumentNullException("parameters"); const string createJobSql = @" insert into HangFire.Job (InvocationData, Arguments, CreatedAt, ExpireAt) values (@invocationData, @arguments, @createdAt, @expireAt); SELECT CAST(SCOPE_IDENTITY() as int)"; var jobId = _connection.Query<int>( createJobSql, new { invocationData = JobHelper.ToJson(invocationData), arguments = JobHelper.ToJson(arguments), createdAt = DateTime.UtcNow, expireAt = DateTime.UtcNow.Add(expireIn) }).Single().ToString(); if (parameters.Count > 0) { var parameterArray = new object[parameters.Count]; int parameterIndex = 0; foreach (var parameter in parameters) { parameterArray[parameterIndex++] = new { jobId = jobId, name = parameter.Key, value = parameter.Value }; } const string insertParameterSql = @" insert into HangFire.JobParameter (JobId, Name, Value) values (@jobId, @name, @value)"; _connection.Execute(insertParameterSql, parameterArray); } return jobId; }
public void Deserialize_CorrectlyDeserializes_AllTheData() { var type = typeof(InvocationDataFacts); var methodInfo = type.GetMethod("Sample"); var serializedData = new InvocationData( type.AssemblyQualifiedName, methodInfo.Name, JobHelper.ToJson(new [] { typeof(string) }), JobHelper.ToJson(new [] { "Hello" })); var job = serializedData.Deserialize(); Assert.Equal(type, job.Type); Assert.Equal(methodInfo, job.Method); Assert.Equal("Hello", job.Arguments[0]); }
public JobPayload FetchNextJob(CancellationToken cancellationToken) { string jobId; string queueName; var queueIndex = 0; do { cancellationToken.ThrowIfCancellationRequested(); queueIndex = (queueIndex + 1) % _queueNames.Count; queueName = _queueNames[queueIndex]; var queueKey = RedisStorage.Prefix + String.Format("queue:{0}", queueName); var fetchedKey = RedisStorage.Prefix + String.Format("queue:{0}:dequeued", queueName); if (queueIndex == 0) { jobId = _redis.BlockingPopAndPushItemBetweenLists( queueKey, fetchedKey, _fetchTimeout); } else { jobId = _redis.PopAndPushItemBetweenLists( queueKey, fetchedKey); } } while (jobId == null); // The job was fetched by the server. To provide reliability, // we should ensure, that the job will be performed and acquired // resources will be disposed even if the server will crash // while executing one of the subsequent lines of code. // The job's processing is splitted into a couple of checkpoints. // Each checkpoint occurs after successful update of the // job information in the storage. And each checkpoint describes // the way to perform the job when the server was crashed after // reaching it. // Checkpoint #1-1. The job was fetched into the fetched list, // that is being inspected by the FetchedJobsWatcher instance. // Job's has the implicit 'Fetched' state. string type = null; string method = null; string parameterTypes = null; string arguments = null; string args = null; using (var pipeline = _redis.CreatePipeline()) { pipeline.QueueCommand(x => x.SetEntryInHash( String.Format(RedisStorage.Prefix + "job:{0}", jobId), "Fetched", JobHelper.ToStringTimestamp(DateTime.UtcNow))); // ServiceStack.Redis library could not queue a command, // that returns IDictionary, so, let's build it using MGET. pipeline.QueueCommand( x => x.GetValuesFromHash( RedisStorage.Prefix + String.Format("job:{0}", jobId), new[] { "Type", "Args", "Method", "Arguments", "ParameterTypes" }), x => { type = x[0]; method = x[2]; parameterTypes = x[4]; args = x[1]; arguments = x[3]; }); pipeline.Flush(); } // Checkpoint #2. The job is in the implicit 'Fetched' state now. // This state stores information about fetched time. The job will // be re-queued when the JobTimeout will be expired. var invocationData = new InvocationData(type, method, parameterTypes); return new JobPayload(jobId, queueName, invocationData) { Args = args, Arguments = arguments }; }
public StateAndInvocationData GetJobStateAndInvocationData(string id) { var jobData = _redis.GetAllEntriesFromHash( String.Format(RedisStorage.Prefix + "job:{0}", id)); if (jobData.Count == 0) return null; string type = null; string method = null; string parameterTypes = null; if (jobData.ContainsKey("Type")) { type = jobData["Type"]; } if (jobData.ContainsKey("Method")) { method = jobData["Method"]; } if (jobData.ContainsKey("ParameterTypes")) { parameterTypes = jobData["ParameterTypes"]; } var invocationData = new InvocationData( type, method, parameterTypes); return new StateAndInvocationData { InvocationData = invocationData, State = jobData.ContainsKey("State") ? jobData["State"] : null, }; }
public JobData GetJobData(string id) { var storedData = Redis.GetAllEntriesFromHash( String.Format(RedisStorage.Prefix + "job:{0}", id)); if (storedData.Count == 0) return null; string type = null; string method = null; string parameterTypes = null; string arguments = null; string createdAt = null; if (storedData.ContainsKey("Type")) { type = storedData["Type"]; } if (storedData.ContainsKey("Method")) { method = storedData["Method"]; } if (storedData.ContainsKey("ParameterTypes")) { parameterTypes = storedData["ParameterTypes"]; } if (storedData.ContainsKey("Arguments")) { arguments = storedData["Arguments"]; } if (storedData.ContainsKey("CreatedAt")) { createdAt = storedData["CreatedAt"]; } Job job = null; JobLoadException loadException = null; var invocationData = new InvocationData(type, method, parameterTypes, arguments); try { job = invocationData.Deserialize(); } catch (JobLoadException ex) { loadException = ex; } return new JobData { Job = job, State = storedData.ContainsKey("State") ? storedData["State"] : null, CreatedAt = JobHelper.FromNullableStringTimestamp(createdAt) ?? DateTime.MinValue, LoadException = loadException }; }
public void Deserialize_ThrowsAnException_WhenMethodCanNotBeFound() { var serializedData = new InvocationData( typeof (TestJob).AssemblyQualifiedName, "NonExistingMethod", JobHelper.ToJson(new Type[0])); Assert.Throws<JobLoadException>( () => MethodData.Deserialize(serializedData)); }
public void SerializedData_IsNotBeingChanged_DuringTheDeserialization() { var serializedData = new InvocationData( typeof (TestJob).AssemblyQualifiedName, null, null); MethodData.Deserialize(serializedData); Assert.Null(serializedData.Method); }
public void Deserialization_FromTheOldFormat_CorrectlySerializesBothTypeAndMethod() { var serializedData = new InvocationData( typeof (TestJob).AssemblyQualifiedName, null, null); var method = MethodData.Deserialize(serializedData); Assert.Equal(typeof(TestJob), method.Type); Assert.Equal(typeof(TestJob).GetMethod("Perform"), method.MethodInfo); Assert.True(method.OldFormat); }