internal void RegisterCompletionOf(Job job)
 {
     Log.DispatcherActivity(Settings.DispatcherId, DispatcherActivity.JobWasCompleted, job, job.ExecutionStatus, job.ExecutionStatus);
 }
 internal void RepublishAsPending(Job job)
 {
     Republish(job, JobStatus.Pending);
 }
 internal void RepublishAsFailed(Job job)
 {
     Republish(job, JobStatus.Failed);
 }
 public bool HasExecutingWorkerFor(Job job)
 {
     lock (ExecutingWorkers)
     {
         IWorker worker;
         if (ExecutingWorkers.TryGetValue(job.WorkerId, out worker))
         {
             return worker.IsExecuting(job);
         }
     }
     return false;
 }
        public bool IsWaitingForCompletionOf(Job job)
        {
            if (job.WorkerId == null)
                return false;

            lock (ExecutingWorkers)
            {
                IWorker worker;
                if (ExecutingWorkers.TryGetValue(job.WorkerId, out worker))
                {
                    return worker.HasCompletionCallback();
                }
            }
            return false;
        }
        public void Execute(Job job, Action<Job> completionCallback, CancellationTokenSource cancellationTokenSource)
        {
            ExecutingJob = job;
            CompletionCallback = completionCallback;
            CancellationTokenSource = cancellationTokenSource;

            bool executionSucceeded;
            var hasTimedOut = false;
            var succeeded = false;

            try
            {
                ExecutingJob.ExecutionStatus = JobStatus.Processing;

                PublishingBus.Publish(JobStatus.Processing.TopicId(), ExecutingJob, StorageType.NonPersistent);

                // Tenta executar o trabalho
                executionSucceeded = TryExecuteWithTimeout();

                // Após executar, checa se não demorou mais tempo que o permitido para concluir a execução
                hasTimedOut = ExecutingJob.HasTimedOut();
                // Se a execução foi bem sucedida e se não demorou tempo demais, 
                // marca para consolidar as alterações de estado e publicar os eventos decorrentes da conclusão da execução com sucesso
                if (executionSucceeded && !hasTimedOut)
                    succeeded = true;
            }
            catch (ThreadAbortException threadAbortException)
            {
                // ThreadAbortException ocorrerá caso o Dispatcher em que o Worker está rodando seja finalizado, 
                // portanto deve ser ignorado e considerado como uma execução não completada
                ExecutingJob.ExecutionException = threadAbortException;
                executionSucceeded = false;
                succeeded = false;
            }
            catch (Exception executionException)
            {
                // Se houve exceção, armazena na solicitação de trabalho para posterior análise
                ExecutingJob.ExecutionException = executionException;
                executionSucceeded = false;
                succeeded = false;
                Log.Error(executionException, String.Format("Error when trying to execute {0}!", GetType().Name));
            }
            
            // Se demorou demais para concluir a execução
            if (hasTimedOut)
            {
                // Um trabalho que não concluiu em tempo é considerado um trabalho que falhou
                ExecutingJob.ExecutionStatus = JobStatus.Failed;
                Timeout();
            }
            // Se a execução concluiu dentro do tempo esperado
            else
            {
                // Armazena o resultado da execução para posterior análise
                ExecutingJob.ExecutionStatus = executionSucceeded ? JobStatus.Succeeded : JobStatus.Failed;
            }

            // Consolida ou cancela as alterações de estado decorrentes da execução do trabalho
            if (succeeded)
            {
                PublishingBus.Publish(JobStatus.Succeeded.TopicId(), ExecutingJob, StorageType.NonPersistent);
                Complete();
            }
            else if (!hasTimedOut)
            {
                PublishingBus.Publish(JobStatus.Failed.TopicId(), ExecutingJob, StorageType.NonPersistent);
                Fail();
            }
            // Executa callback de confirmação da execução
            if (HasCompletionCallback())
                CompletionCallback(ExecutingJob);
        }
 private void FailJobExecution(Job job)
 {
     if (job.ExecutionException != null)
     {
         Log.DispatcherActivity(
             Repository.Settings.DispatcherId,
             DispatcherActivity.BackgroundThreadException,
             job,
             JobStatus.Failed,
             JobStatus.Failed
         );
     }
     Repository.RepublishAsFailed(job);
 }
 private static IWorker NewWorkerFor(Job job)
 {
     var worker = DependencyResolver.Get<Worker>(job.WorkerType);
     return worker;
 }
        private void ProcessAsCompleted(Job job)
        {
            Repository.RegisterCompletionOf(job);

            switch (job.ExecutionStatus)
            {
                case JobStatus.Succeeded:
                    break;
                case JobStatus.Failed:
                    CheckIfShallRepeatOrLogTheExecutionOf(job);
                    break;
                default:
                    Debug.Fail(String.Format("Invalid execution status for work request {0}", job.MessageId));
                    break;
            }
        }
        private IWorker InitializeWorkerAndJob(Job job)
        {
            var worker = NewWorkerFor(job);
            Debug.Assert(worker != null, "worker != null");
            job.WorkerId = worker.WorkerId;

            lock (ExecutingWorkers)
            {
                ExecutingWorkers[job.WorkerId] = worker;
            }

            //Repository.SubscribeToWorkerLifeSignal(job.WorkerId);

            return worker;
        }
 private void ExecuteJob(Job job, IWorker worker)
 {
     try
     {
         Log.Debug("Dispatching {0} to {1}", job.GetType().FullName, worker.GetType().FullName);
         worker.Execute(job, ProcessAsCompleted, CancellationTokenForExecutionOfJob);
     }
     finally
     {
         FinalizeWorker(worker);
     }
 }
        private static void ApplyConfigurationToJob(Job job, JobConfiguration configuration)
        {
            job.RequestMaxAttempts = configuration.RequestMaxAttempts;
            job.RequestTimeout = configuration.RequestTimeout;
            job.ProcessingAttempts += 1;

            job.RequestMaxTime = configuration.RequestTimeout == Timeout.InfiniteTimeSpan
                ? Timeout.InfiniteTimeSpan
                : TimeSpan.FromSeconds(configuration.RequestTimeout.TotalSeconds * configuration.RequestMaxAttempts);

            job.WorkerType = configuration.JobAndWorkerType.WorkerType.Type;
        }
        private void DispatchJob(Job job)
        {
            var configuration = Repository.Settings.JobConfigurations.Single(c => c.JobAndWorkerType.JobType.Type == job.GetType());

            ApplyConfigurationToJob(job, configuration);

            var worker = InitializeWorkerAndJob(job);

            Log.DispatcherActivity(Repository.Settings.DispatcherId, DispatcherActivity.JobWasDispatched, job, job.ExecutionStatus, job.ExecutionStatus);

            ExecuteJob(job, worker);
        }
 private void ReceiveJob(Job job)
 {
     // Since ReceiveJob is called asyncronously, this lock avoid reentrance while processing a received work request
     lock (ReceivingJobLock)
     {
         Log.DispatcherActivity(Repository.Settings.DispatcherId, DispatcherActivity.JobWasReceived, job, job.ExecutionStatus, job.ExecutionStatus);
         DispatchJob(job);
     }
 }
        private void Republish(Job job, JobStatus newRequestStatus)
        {
            var oldRequestStatus = job.ExecutionStatus;

            job.ExecutionStatus = newRequestStatus;

            Log.DispatcherActivity(Settings.DispatcherId, DispatcherActivity.JobWasRepublished, job, oldRequestStatus, newRequestStatus);

            PublishingBus.Publish(newRequestStatus.TopicId(), job);
        }
 private void CheckIfShallRepeatOrLogTheExecutionOf(Job job)
 {
     switch (job.FailureAction)
     {
         case JobFailureAction.Repeat:
             if (job.HasExceededMaxAttempts())
                 FailJobExecution(job);
             else
             {
                 Repository.RepublishAsPending(job);
             }
             break;
         case JobFailureAction.Log:
             FailJobExecution(job);
             break;
     }
 }
        internal static void DispatcherActivity(this Logger log, DispatcherId dispatcherId, DispatcherActivity activity, Job job, JobStatus oldStatus, JobStatus? newStatus = null)
        {
            var logEntry = new DispatcherActivityLogEntry
            {
                DispatcherId = dispatcherId,
                Activity = activity,
                Job = job,
                OldStatus = oldStatus,
                NewStatus = newStatus ?? oldStatus
            };

            log.Info(logEntry);
        }
 public bool IsExecuting(Job job)
 {
     return ExecutingJob == job;
 }