public void CopyCtor_CopiesItemsDictionary_FromTheGivenContext()
        {
            var context = CreateContext();
            var contextCopy = new CreateContext(context);

            Assert.Same(context.Items, contextCopy.Items);
        }
        public BackgroundJob Create(CreateContext context)
        {
            var parameters = context.Parameters.ToDictionary(x => x.Key, x => JobHelper.ToJson(x.Value));

            var createdAt = DateTime.UtcNow;
            var jobId = context.Connection.CreateExpiredJob(
                context.Job,
                parameters,
                createdAt,
                TimeSpan.FromHours(1));

            var backgroundJob = new BackgroundJob(jobId, context.Job, createdAt);

            if (context.InitialState != null)
            {
                using (var transaction = context.Connection.CreateWriteTransaction())
                {
                    var applyContext = new ApplyStateContext(
                        context.Storage,
                        context.Connection,
                        transaction,
                        backgroundJob,
                        context.InitialState,
                        null);

                    _stateMachine.ApplyState(applyContext);

                    transaction.Commit();
                }
            }

            return backgroundJob;
        }
        internal ClientExceptionContext(CreateContext createContext, Exception exception)
            : base(createContext)
        {
            if (exception == null) throw new ArgumentNullException("exception");

            Exception = exception;
        }
        public string Run(CreateContext context, IJobCreator creator)
        {
            if (context == null) throw new ArgumentNullException("context");
            if (creator == null) throw new ArgumentNullException("creator");

            var filterInfo = GetFilters(context.Job);

            try
            {
                var createdContext = CreateWithFilters(context, creator, filterInfo.ClientFilters);
                return createdContext.JobId;
            }
            catch (Exception ex)
            {
                var exceptionContext = new ClientExceptionContext(context, ex);

                InvokeExceptionFilters(exceptionContext, filterInfo.ClientExceptionFilters);
                if (!exceptionContext.ExceptionHandled)
                {
                    throw;
                }

                return null;
            }
        }
 private CreatedContext CreateContext()
 {
     var connection = new Mock<IStorageConnection>();
     var job = Job.FromExpression(() => TestMethod());
     var state = new Mock<IState>();
     
     var createContext = new CreateContext(connection.Object, job, state.Object);
     return new CreatedContext(createContext, JobId, true, _exception);
 }
Exemple #6
0
 internal CreatedContext(
     CreateContext context, 
     bool canceled, 
     Exception exception)
     : base(context)
 {
     Canceled = canceled;
     Exception = exception;
 }
        public ClientExceptionContextFacts()
        {
            var connection = new Mock<IStorageConnection>();
            var job = Job.FromExpression(() => TestMethod());
            var state = new Mock<IState>();

            _createContext = new CreateContext(
                connection.Object, job, state.Object);
        }
        public void Ctor_CanceledProperty_IsFalseByDefault()
        {
            var connection = new Mock<IStorageConnection>();
            var job = Job.FromExpression(() => TestMethod());
            var state = new Mock<IState>();
            var stateMachineFactory = new Mock<IStateMachineFactory>();

            var createContext = new CreateContext(
                connection.Object, stateMachineFactory.Object, job, state.Object);
            var context = new CreatingContext(createContext);

            Assert.False(context.Canceled);
        }
        public void Ctor_CorrectlySetsAllProperties()
        {
            var connection = new Mock<IStorageConnection>();
            var job = Job.FromExpression(() => TestMethod());
            var state = new Mock<IState>();
            var exception = new Exception();
            var stateMachineFactory = new Mock<IStateMachineFactory>();

            var createContext = new CreateContext(
                connection.Object, stateMachineFactory.Object, job, state.Object);
            var context = new CreatedContext(createContext, true, exception);

            Assert.True(context.Canceled);
            Assert.Same(exception, context.Exception);
        }
Exemple #10
0
        private static void CreateWithFilters(
            CreateContext context,
            IEnumerable<IClientFilter> filters)
        {
            var preContext = new CreatingContext(context);
            Func<CreatedContext> continuation = () =>
            {
                context.CreateJob();
                return new CreatedContext(context, false, null);
            };

            var thunk = filters.Reverse().Aggregate(continuation,
                (next, filter) => () => InvokeClientFilter(filter, preContext, next));

            thunk();
        }
        private CreatedContext CreateWithFilters(
            CreateContext context,
            IEnumerable <IClientFilter> filters)
        {
            var preContext = new CreatingContext(context);
            Func <CreatedContext> continuation = () =>
            {
                var backgroundJob = _innerFactory.Create(context);
                return(new CreatedContext(context, backgroundJob, false, null));
            };

            var thunk = filters.Reverse().Aggregate(continuation,
                                                    (next, filter) => () => InvokeClientFilter(filter, preContext, next));

            return(thunk());
        }
        private CreatedContext CreateWithFilters(
            CreateContext context, 
            IEnumerable<IClientFilter> filters)
        {
            var preContext = new CreatingContext(context);
            Func<CreatedContext> continuation = () =>
            {
                var backgroundJob = _innerFactory.Create(context);
                return new CreatedContext(context, backgroundJob, false, null);
            };

            var thunk = filters.Reverse().Aggregate(continuation,
                (next, filter) => () => InvokeClientFilter(filter, preContext, next));

            return thunk();
        }
Exemple #13
0
        private static void CreateWithFilters(
            CreateContext context,
            IEnumerable <IClientFilter> filters)
        {
            var preContext = new CreatingContext(context);
            Func <CreatedContext> continuation = () =>
            {
                context.CreateJob();
                return(new CreatedContext(context, false, null));
            };

            var thunk = filters.Reverse().Aggregate(continuation,
                                                    (next, filter) => () => InvokeClientFilter(filter, preContext, next));

            thunk();
        }
        private static CreatedContext CreateWithFilters(
            CreateContext context,
            IJobCreator creator,
            IEnumerable<IClientFilter> filters)
        {
            var preContext = new CreatingContext(context);
            Func<CreatedContext> continuation = () =>
            {
                var jobId = creator.CreateJob(context.Job, preContext.Parameters, context.InitialState);
                return new CreatedContext(context, jobId, false, null);
            };

            var thunk = filters.Reverse().Aggregate(continuation,
                (next, filter) => () => InvokeClientFilter(filter, preContext, next));

            return thunk();
        }
        public PreserveCultureAttributeFacts()
        {
            _connection = new Mock<IStorageConnection>();
            var job = Job.FromExpression(() => Sample());
            var state = new Mock<IState>();

            var createContext = new CreateContext(
                _connection.Object, job, state.Object);
            _creatingContext = new CreatingContext(createContext);

            var workerContext = new WorkerContextMock();

            var performContext = new PerformContext(
                workerContext.Object, _connection.Object, JobId, job, DateTime.UtcNow, new Mock<IJobExecutionContext>().Object);
            _performingContext = new PerformingContext(performContext);
            _performedContext = new PerformedContext(performContext, null, false, null);
        }
        private static CreatedContext CreateWithFilters(
            CreateContext context,
            IJobCreator creator,
            IEnumerable <IClientFilter> filters)
        {
            var preContext = new CreatingContext(context);
            Func <CreatedContext> continuation = () =>
            {
                var jobId = creator.CreateJob(context.Job, preContext.Parameters, context.InitialState);
                return(new CreatedContext(context, jobId, false, null));
            };

            var thunk = filters.Reverse().Aggregate(continuation,
                                                    (next, filter) => () => InvokeClientFilter(filter, preContext, next));

            return(thunk());
        }
        public PreserveCultureAttributeFacts()
        {
            _connection = new Mock<IStorageConnection>();

            var storage = new Mock<JobStorage>();
            var backgroundJob = new BackgroundJobMock { Id = JobId };
            var state = new Mock<IState>();

            var createContext = new CreateContext(
                storage.Object, _connection.Object, backgroundJob.Job, state.Object);
            _creatingContext = new CreatingContext(createContext);

            var performContext = new PerformContext(
                _connection.Object, backgroundJob.Object, new Mock<IJobCancellationToken>().Object);
            _performingContext = new PerformingContext(performContext);
            _performedContext = new PerformedContext(performContext, null, false, null);
        }
Exemple #18
0
        public void Run(CreateContext context)
        {
            if (context == null) throw new ArgumentNullException("context");

            var filterInfo = GetFilters(context.Job);

            try
            {
                CreateWithFilters(context, filterInfo.ClientFilters);
            }
            catch (Exception ex)
            {
                var exceptionContext = new ClientExceptionContext(context, ex);

                InvokeExceptionFilters(exceptionContext, filterInfo.ClientExceptionFilters);
                if (!exceptionContext.ExceptionHandled)
                {
                    throw;
                }
            }
        }
        public BackgroundJob Create(CreateContext context)
        {
            if (context == null) throw new ArgumentNullException(nameof(context));

            var filterInfo = GetFilters(context.Job);

            try
            {
                var createdContext = CreateWithFilters(context, filterInfo.ClientFilters);
                return createdContext.BackgroundJob;
            }
            catch (Exception ex)
            {
                var exceptionContext = new ClientExceptionContext(context, ex);

                InvokeExceptionFilters(exceptionContext, filterInfo.ClientExceptionFilters);
                if (!exceptionContext.ExceptionHandled)
                {
                    throw;
                }

                return null;
            }
        }
        public BackgroundJob Create(CreateContext context)
        {
            var parameters = context.Parameters.ToDictionary(
                x => x.Key,
                x => SerializationHelper.Serialize(x.Value, SerializationOption.User));

            var createdAt = DateTime.UtcNow;
            var jobId     = context.Connection.CreateExpiredJob(
                context.Job,
                parameters,
                createdAt,
                TimeSpan.FromDays(30));

            var backgroundJob = new BackgroundJob(jobId, context.Job, createdAt);

            if (context.InitialState != null)
            {
                using (var transaction = context.Connection.CreateWriteTransaction())
                {
                    var applyContext = new ApplyStateContext(
                        context.Storage,
                        context.Connection,
                        transaction,
                        backgroundJob,
                        context.InitialState,
                        oldStateName: null,
                        profiler: context.Profiler);

                    _stateMachine.ApplyState(applyContext);

                    transaction.Commit();
                }
            }

            return(backgroundJob);
        }
Exemple #21
0
        public void Run(CreateContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            var filterInfo = GetFilters(context.Job);

            try
            {
                CreateWithFilters(context, filterInfo.ClientFilters);
            }
            catch (Exception ex)
            {
                var exceptionContext = new ClientExceptionContext(context, ex);

                InvokeExceptionFilters(exceptionContext, filterInfo.ClientExceptionFilters);
                if (!exceptionContext.ExceptionHandled)
                {
                    throw;
                }
            }
        }
Exemple #22
0
 internal CreateContext(CreateContext context)
     : this(context.Connection, context.Job, context.InitialState)
 {
     Items = context.Items;
 }
Exemple #23
0
        public void CopyCtor_CopiesTheFactThatJobWasCreated()
        {
            var context = CreateContext();
            context.CreateJob();

            var contextCopy = new CreateContext(context);

            Assert.Throws<InvalidOperationException>(
                () => contextCopy.SetJobParameter("name", "value"));
        }
Exemple #24
0
 internal CreateContext(CreateContext context)
     : this(context.Connection, context.Job, context.InitialState)
 {
     Items = context.Items;
 }
        /// <inheritdoc />
        public string Create(Job job, IState state)
        {
            if (job == null) throw new ArgumentNullException("job");
            if (state == null) throw new ArgumentNullException("state");

            try
            {
                using (var connection = _storage.GetConnection())
                {
                    var context = new CreateContext(connection, _stateMachineFactory, job, state);
                    _process.Run(context);

                    return context.JobId;
                }
            }
            catch (Exception ex)
            {
                throw new CreateJobFailedException("Job creation process has bee failed. See inner exception for details", ex);
            }
        }
Exemple #26
0
 internal CreateContext([NotNull] CreateContext context)
     : this(context.Storage, context.Connection, context.Job, context.InitialState)
 {
     Items      = context.Items;
     Parameters = context.Parameters;
 }
        private CreatingContext CreateContext()
        {
            var storage = new Mock<JobStorage>();
            var connection = new Mock<IStorageConnection>();
            var job = Job.FromExpression(() => TestMethod());
            var state = new Mock<IState>();

            var createContext = new CreateContext(storage.Object, connection.Object, job, state.Object);
            return new CreatingContext(createContext);            
        }
        /// <inheritdoc />
        public string Create(Job job, IState state)
        {
            if (job == null) throw new ArgumentNullException("job");
            if (state == null) throw new ArgumentNullException("state");

            try
            {
                using (var connection = _storage.GetConnection())
                {
                    var context = new CreateContext(_storage, connection, job, state);
                    var backroundJob = _factory.Create(context);

                    return backroundJob != null ? backroundJob.Id : null;
                }
            }
            catch (Exception ex)
            {
                throw new BackgroundJobClientException("Background job creation failed. See inner exception for details.", ex);
            }
        }
Exemple #29
0
        public void CopyCtor_CopiesJobId_WhenItWasSet()
        {
            _stateMachine.Setup(x => x.CreateInState(
                _job, It.IsAny<Dictionary<string, string>>(), _state.Object))
                .Returns("id");

            var context = CreateContext();
            context.CreateJob();

            var contextCopy = new CreateContext(context);

            Assert.Equal("id", contextCopy.JobId);
        }
Exemple #30
0
        public BackgroundJob Create(CreateContext context)
        {
            var attemptsLeft = Math.Max(RetryAttempts, 0);
            var parameters   = context.Parameters.ToDictionary(
                x => x.Key,
                x => SerializationHelper.Serialize(x.Value, SerializationOption.User));

            var createdAt = DateTime.UtcNow;

            // Retry may cause multiple background jobs to be created, especially when there's
            // a timeout-related exception. But initialization attempt will be performed only
            // for the most recent job, leaving all the previous ones in a non-initialized state
            // and making them invisible to other parts of the system, since no one knows their
            // identifiers. Since they also will be eventually expired leaving no trace, we can
            // consider that only one background job is created, regardless of retry attempts
            // number.
            var jobId = RetryOnException(ref attemptsLeft, _ => context.Connection.CreateExpiredJob(
                                             context.Job,
                                             parameters,
                                             createdAt,
                                             TimeSpan.FromDays(30)));

            if (String.IsNullOrEmpty(jobId))
            {
                return(null);
            }

            var backgroundJob = new BackgroundJob(jobId, context.Job, createdAt);

            if (context.InitialState != null)
            {
                RetryOnException(ref attemptsLeft, attempt =>
                {
                    if (attempt > 0)
                    {
                        // Normally, a distributed lock should be applied when making a retry, since
                        // it's possible to get a timeout exception, when transaction was actually
                        // committed. But since background job can't be returned to a position where
                        // its state is null, and since only the current thread knows the job's identifier
                        // when its state is null, and since we shouldn't do anything when it's non-null,
                        // there will be no any race conditions.
                        var data = context.Connection.GetJobData(jobId);
                        if (data == null)
                        {
                            throw new InvalidOperationException($"Was unable to initialize a background job '{jobId}', because it doesn't exists.");
                        }

                        if (!String.IsNullOrEmpty(data.State))
                        {
                            return;
                        }
                    }

                    using (var transaction = context.Connection.CreateWriteTransaction())
                    {
                        var applyContext = new ApplyStateContext(
                            context.Storage,
                            context.Connection,
                            transaction,
                            backgroundJob,
                            context.InitialState,
                            oldStateName: null,
                            profiler: context.Profiler);

                        StateMachine.ApplyState(applyContext);

                        transaction.Commit();
                    }
                });
            }

            return(backgroundJob);
        }
        private void TryScheduleJob(
            JobStorage storage,
            IStorageConnection connection, 
            string recurringJobId, 
            IReadOnlyDictionary<string, string> recurringJob)
        {
            var serializedJob = JobHelper.FromJson<InvocationData>(recurringJob["Job"]);
            var job = serializedJob.Deserialize();
            var cron = recurringJob["Cron"];
            var cronSchedule = CrontabSchedule.Parse(cron);

            try
            {
                var timeZone = recurringJob.ContainsKey("TimeZoneId")
                    ? TimeZoneInfo.FindSystemTimeZoneById(recurringJob["TimeZoneId"])
                    : TimeZoneInfo.Utc;

                var nowInstant = _instantFactory(cronSchedule, timeZone);
                var changedFields = new Dictionary<string, string>();

                var lastInstant = GetLastInstant(recurringJob, nowInstant);
                
                if (nowInstant.GetNextInstants(lastInstant).Any())
                {
                    var state = new EnqueuedState { Reason = "Triggered by recurring job scheduler" };
                    if (recurringJob.ContainsKey("Queue") && !String.IsNullOrEmpty(recurringJob["Queue"]))
                    {
                        state.Queue = recurringJob["Queue"];
                    }

                    var context = new CreateContext(storage, connection, job, state);
                    context.Parameters["RecurringJobId"] = recurringJobId;

                    var backgroundJob = _factory.Create(context);
                    var jobId = backgroundJob?.Id;

                    if (String.IsNullOrEmpty(jobId))
                    {
                        Logger.Debug($"Recurring job '{recurringJobId}' execution at '{nowInstant.NowInstant}' has been canceled.");
                    }

                    changedFields.Add("LastExecution", JobHelper.SerializeDateTime(nowInstant.NowInstant));
                    changedFields.Add("LastJobId", jobId ?? String.Empty);
                }
                
                // Fixing old recurring jobs that doesn't have the CreatedAt field
                if (!recurringJob.ContainsKey("CreatedAt"))
                {
                    changedFields.Add("CreatedAt", JobHelper.SerializeDateTime(nowInstant.NowInstant));
                }
                    
                changedFields.Add("NextExecution", nowInstant.NextInstant.HasValue ? JobHelper.SerializeDateTime(nowInstant.NextInstant.Value) : null);

                connection.SetRangeInHash(
                    $"recurring-job:{recurringJobId}",
                    changedFields);
            }
#if NETFULL
            catch (TimeZoneNotFoundException ex)
            {
#else
            catch (Exception ex)
            {
                // https://github.com/dotnet/corefx/issues/7552
                if (!ex.GetType().Name.Equals("TimeZoneNotFoundException")) throw;
#endif

                Logger.ErrorException(
                    $"Recurring job '{recurringJobId}' was not triggered: {ex.Message}.",
                    ex);
            }

        }
Exemple #32
0
 public CreatingContext(CreateContext context)
     : base(context)
 {
 }
Exemple #33
0
        public void CopyCtor_CopiesJobParameters_FromTheGivenContext()
        {
            var context = CreateContext();
            context.SetJobParameter("name", "value");
            var contextCopy = new CreateContext(context);

            var value = contextCopy.GetJobParameter<string>("name");

            Assert.Equal("value", value);
        }
        public void Trigger(string recurringJobId)
        {
            if (recurringJobId == null) throw new ArgumentNullException(nameof(recurringJobId));

            using (var connection = _storage.GetConnection())
            {
                var hash = connection.GetAllEntriesFromHash($"recurring-job:{recurringJobId}");
                if (hash == null)
                {
                    return;
                }
                
                var job = JobHelper.FromJson<InvocationData>(hash["Job"]).Deserialize();
                var state = new EnqueuedState { Reason = "Triggered using recurring job manager" };

                if (hash.ContainsKey("Queue"))
                {
                    state.Queue = hash["Queue"];
                }

                var context = new CreateContext(_storage, connection, job, state);
                context.Parameters["RecurringJobId"] = recurringJobId;
                _factory.Create(context);
            }
        }
Exemple #35
0
        public void CopyCtor_CopiesJobId_FromTheGivenContext()
        {
            var context = CreateContext();
            var contextCopy = new CreateContext(context);

            Assert.Same(context.JobId, contextCopy.JobId);
        }