internal JobWorker(JobWorkerBuilder builder)
 {
     this.jobWorkerBuilder        = builder;
     this.source                  = new CancellationTokenSource();
     this.logger                  = builder.LoggerFactory?.CreateLogger <JobWorker>();
     this.jobHandler              = jobWorkerBuilder.Handler();
     this.autoCompletion          = builder.AutoCompletionEnabled();
     this.pollInterval            = jobWorkerBuilder.PollInterval();
     this.activateJobsCommand     = jobWorkerBuilder.Command;
     this.maxJobsActive           = jobWorkerBuilder.Command.Request.MaxJobsToActivate;
     this.thresholdJobsActivation = maxJobsActive * 0.6;
 }
Beispiel #2
0
        /// <summary>
        /// Opens the configured JobWorker to activate jobs in the given poll interval
        /// and handle with the given handler.
        /// </summary>
        internal void Open()
        {
            isRunning = true;
            var cancellationToken = source.Token;

            activateJobsCommand = jobWorkerBuilder.Command;
            maxJobsActive       = jobWorkerBuilder.Command.Request.MaxJobsToActivate;

            // Create options for blocks
            var bufferOptions = new DataflowBlockOptions
            {
                CancellationToken = cancellationToken,
                EnsureOrdered     = false
            };

            var executionOptions = new ExecutionDataflowBlockOptions
            {
                MaxDegreeOfParallelism = jobWorkerBuilder.ThreadCount,
                CancellationToken      = cancellationToken,
                EnsureOrdered          = false
            };

            // Buffer for polled jobs
            var input = new BufferBlock <IJob>(bufferOptions);

            // Transformblock to process polled jobs
            var transformer = new TransformBlock <IJob, IJob>(async activatedJob =>
            {
                var jobClient = JobClientWrapper.Wrap(jobWorkerBuilder.JobClient);

                try
                {
                    await jobHandler(jobClient, activatedJob);
                    await TryToAutoCompleteJob(jobClient, activatedJob);
                }
                catch (Exception exception)
                {
                    await FailActivatedJob(jobClient, activatedJob, cancellationToken, exception);
                }
                finally
                {
                    jobClient.Reset();
                }

                return(activatedJob);
            },
                                                              executionOptions);

            // Action block to finalize handled tasks
            var output = new ActionBlock <IJob>(activatedJob => { currentJobsActive--; },
                                                executionOptions);

            // Link blocks
            input.LinkTo(transformer);
            transformer.LinkTo(output);

            // Start polling
            Task.Run(async() =>
            {
                while (!source.IsCancellationRequested)
                {
                    if (currentJobsActive >= maxJobsActive)
                    {
                        await Task.Delay(pollInterval);
                        continue;
                    }

                    var jobCount = maxJobsActive - currentJobsActive;
                    activateJobsCommand.MaxJobsToActivate(jobCount);

                    try
                    {
                        var response = await activateJobsCommand.Send(null, cancellationToken);

                        logger?.LogDebug(
                            "Job worker ({worker}) activated {activatedCount} of {requestCount} successfully.",
                            activateJobsCommand.Request.Worker,
                            response.Jobs.Count,
                            jobCount);

                        foreach (var job in response.Jobs)
                        {
                            await input.SendAsync(job);
                            currentJobsActive++;
                        }
                    }
                    catch (RpcException rpcException)
                    {
                        LogRpcException(rpcException);
                    }
                }
            },
                     cancellationToken).ContinueWith(
                t => logger?.LogError(t.Exception, "Job polling failed."),
                TaskContinuationOptions.OnlyOnFaulted);

            var command = jobWorkerBuilder.Command;

            logger?.LogDebug(
                "Job worker ({worker}) for job type {type} has been opened.",
                command.Request.Worker,
                command.Request.Type);
        }