/// <summary>
 /// Create document
 /// </summary>
 /// <param name="model"></param>
 /// <param name="jobId"></param>
 /// <returns></returns>
 public static ProcessingStatusDocument ToDocumentModel(
     this ProcessingStatusModel model, string jobId)
 {
     return(new ProcessingStatusDocument {
         LastKnownHeartbeat = model.LastKnownHeartbeat,
         LastKnownState = model.LastKnownState,
         ProcessMode = model.ProcessMode,
         JobId = jobId
     });
 }
 /// <summary>
 /// Clone
 /// </summary>
 /// <param name="model"></param>
 /// <returns></returns>
 public static ProcessingStatusModel Clone(this ProcessingStatusModel model)
 {
     if (model == null)
     {
         return(null);
     }
     return(new ProcessingStatusModel {
         LastKnownHeartbeat = model.LastKnownHeartbeat,
         LastKnownState = model.LastKnownState,
         ProcessMode = model.ProcessMode
     });
 }
示例#3
0
 /// <summary>
 /// Create model
 /// </summary>
 /// <param name="model"></param>
 public static ProcessingStatusApiModel ToApiModel(
     this ProcessingStatusModel model)
 {
     if (model == null)
     {
         return(null);
     }
     return(new ProcessingStatusApiModel {
         LastKnownHeartbeat = model.LastKnownHeartbeat,
         LastKnownState = model.LastKnownState?.DeepClone(),
         ProcessMode = (Api.Jobs.Models.ProcessMode?)model.ProcessMode
     });
 }
        /// <inheritdoc/>
        public async Task <HeartbeatResultModel> SendHeartbeatAsync(HeartbeatModel heartbeat,
                                                                    CancellationToken ct)
        {
            if (_workerRepository != null)
            {
                await _workerRepository.AddOrUpdate(heartbeat.Worker);
            }

            var result = new HeartbeatResultModel {
                HeartbeatInstruction = HeartbeatInstruction.Keep,
                LastActiveHeartbeat  = null,
                UpdatedJob           = null
            };

            if (heartbeat.Job == null)
            {
                // Worker heartbeat
                return(result);
            }

            var job = await _jobRepository.UpdateAsync(heartbeat.Job.JobId, existingJob => {
                if (existingJob.GetHashSafe() != heartbeat.Job.JobHash)
                {
                    // job was updated - instruct worker to reset
                    result.UpdatedJob = new JobProcessingInstructionModel {
                        Job         = existingJob,
                        ProcessMode = heartbeat.Job.ProcessMode
                    };
                }

                if (existingJob.LifetimeData == null)
                {
                    existingJob.LifetimeData = new JobLifetimeDataModel();
                }

                if (existingJob.LifetimeData.Status == JobStatus.Canceled ||
                    existingJob.LifetimeData.Status == JobStatus.Deleted)
                {
                    result.HeartbeatInstruction = HeartbeatInstruction.CancelProcessing;
                    result.UpdatedJob           = null;
                    result.LastActiveHeartbeat  = null;
                }

                if (result.HeartbeatInstruction == HeartbeatInstruction.Keep)
                {
                    existingJob.LifetimeData.Status = heartbeat.Job.Status;
                }

                var processingStatus = new ProcessingStatusModel {
                    LastKnownHeartbeat = DateTime.UtcNow,
                    LastKnownState     = heartbeat.Job.State,
                    ProcessMode        = // Unset processing mode to do correct calculation of active agents
                                         heartbeat.Job.Status == JobStatus.Active ?
                                         heartbeat.Job.ProcessMode : (ProcessMode?)null
                };

                if (existingJob.LifetimeData.ProcessingStatus == null)
                {
                    existingJob.LifetimeData.ProcessingStatus = new Dictionary <string, ProcessingStatusModel>();
                }
                existingJob.LifetimeData.ProcessingStatus[heartbeat.Worker.WorkerId] = processingStatus;

                var numberOfActiveAgents = existingJob.LifetimeData.ProcessingStatus
                                           .Count(j =>
                                                  j.Value.ProcessMode == ProcessMode.Active &&
                                                  j.Value.LastKnownHeartbeat > DateTime.UtcNow.Subtract(_jobOrchestratorConfig.JobStaleTime));

                if (processingStatus.ProcessMode == ProcessMode.Passive &&
                    numberOfActiveAgents < existingJob.RedundancyConfig.DesiredActiveAgents)
                {
                    var lastActiveHeartbeat = existingJob.LifetimeData.ProcessingStatus
                                              .Where(s => s.Value.ProcessMode == ProcessMode.Active)
                                              .OrderByDescending(s => s.Value.LastKnownHeartbeat)
                                              .Select(s => s.Value.LastKnownHeartbeat)
                                              .FirstOrDefault();

                    // Switch this passive agent to active
                    result.HeartbeatInstruction = HeartbeatInstruction.SwitchToActive;
                    result.LastActiveHeartbeat  = lastActiveHeartbeat;

                    existingJob.LifetimeData.ProcessingStatus[heartbeat.Worker.WorkerId].ProcessMode =
                        ProcessMode.Active;
                }
                return(Task.FromResult(true));
            }, ct);

            return(result);
        }