/// <summary> /// This method should never be called by a sub-class. /// This method is protected only to allow inheritors to create additional workers by overriding this method. /// </summary> protected virtual void CreateWorkers() { // ReSharper disable InconsistentlySynchronizedField MessageConsumer.Connect(); var errorWorker = new WorkerScheduled(_settings.ErrorQueueName, _settings.ScheduledWorkersBatchSize, ServiceScopeFactory, ServiceScope.GetRequiredService <IJobLogger <WorkerScheduled> >()); errorWorker.Error += OnWorkerError; Workers.Add(errorWorker); for (var i = 0; i < _settings.ScheduledWorkersCount; i++) { var queueName = string.Format(_settings.ScheduledQueueNameTemplate, i); var worker = new WorkerScheduled(queueName, _settings.ScheduledWorkersBatchSize, ServiceScopeFactory, ServiceScope.GetRequiredService <IJobLogger <WorkerScheduled> >()); worker.Error += OnWorkerError; Workers.Add(worker); } for (var i = 0; i < _settings.PeriodicWorkersCount; i++) { var queueName = string.Format(_settings.PeriodicQueueNameTemplate, i); var worker = new WorkerScheduled(queueName, _settings.PeriodicWorkersBatchSize, ServiceScopeFactory, ServiceScope.GetRequiredService <IJobLogger <WorkerScheduled> >()); worker.Error += OnWorkerError; Workers.Add(worker); } for (var i = 0; i < _settings.ImmediateWorkersCount; i++) { var queueName = string.Format(_settings.ImmediateQueueNameTemplate, i); var worker = new WorkerImmediate(queueName, _settings.ImmediateWorkersBatchSize, _settings.MaxDegreeOfParallelismPerWorker, ServiceScopeFactory, ServiceScope.GetRequiredService <IJobLogger <WorkerImmediate> >()); worker.Error += OnWorkerError; Workers.Add(worker); } for (var i = 0; i < _settings.LongRunningWorkersCount; i++) { var queueName = string.Format(_settings.LongRunningQueueNameTemplate, i); var worker = new WorkerImmediate(queueName, _settings.LongRunningWorkersBatchSize, _settings.MaxDegreeOfParallelismPerWorker, ServiceScopeFactory, ServiceScope.GetRequiredService <IJobLogger <WorkerImmediate> >()); worker.Error += OnWorkerError; Workers.Add(worker); } // ReSharper restore InconsistentlySynchronizedField }
public SqlServerMessageReceiver(string queueName, bool singleActiveConsumer, IJobServiceScopeFactory scopeFactory, IJobLogger <SqlServerMessageReceiver <TDbContext> > logger) { _scopeFactory = scopeFactory; _scope = scopeFactory.CreateScope(); _queueName = queueName; _singleActiveConsumer = singleActiveConsumer; _sqlDialect = _scope.GetRequiredService <ISqlDialect>(); _timeProvider = _scope.GetRequiredService <ITimeProvider>(); _logger = logger; _instanceName = $"{Environment.MachineName}/{Guid.NewGuid()}"; _timer = _scope.GetRequiredService <ITimer>(); _timer.TimeElapsed += TimerCallback; }
public WorkerCoordinator(IJobServiceFactory serviceFactory, IJobLogger <WorkerCoordinator> logger = null) { ServiceScopeFactory = serviceFactory.GetRequiredService <IJobServiceScopeFactory>(); ServiceScope = ServiceScopeFactory.CreateScope(); _settings = ServiceScope.GetRequiredService <MassiveJobsSettings>(); _reconnectTimer = ServiceScope.GetRequiredService <ITimer>(); _reconnectTimer.TimeElapsed += Reconnect; Workers = new List <IWorker>(); Logger = logger ?? ServiceScope.GetRequiredService <IJobLogger <WorkerCoordinator> >(); MessageConsumer = ServiceScope.GetRequiredService <IMessageConsumer>(); MessageConsumer.Disconnected += MessageBrokerDisconnected; }
public IBrokerTransaction BeginTransaction(IJobServiceScope scope) { var dbContext = scope.GetRequiredService <TDbContext>(); var tx = dbContext.Database.BeginTransaction(); return(new BrokerTransaction(tx)); }
protected bool TryDeserializeJob(RawMessage rawMessage, IJobServiceScope scope, out JobInfo job) { job = null; var argsTag = rawMessage.TypeTag; if (string.IsNullOrEmpty(argsTag)) { return(false); } var serializer = scope.GetRequiredService <IJobSerializer>(); var typeProvider = scope.GetRequiredService <IJobTypeProvider>(); job = serializer.Deserialize(rawMessage.Body, argsTag, typeProvider); return(job != null); }
public void AckMessageProcessed(IJobServiceScope scope, ulong deliveryTag) { var dbContext = scope.GetRequiredService <TDbContext>(); var affectedCount = _sqlDialect.MessageQueueAckProcessed(dbContext, _instanceName, _timeProvider.GetCurrentTimeUtc()); if (affectedCount != 1) { throw new Exception($"Ack failed. Expected 1 row, but instead, {affectedCount} rows were affected"); } }
protected Worker(string queueName, int batchSize, int masMaxDegreeOfParallelism, bool singleActiveConsumer, IJobServiceScopeFactory serviceScopeFactory, IJobLogger <Worker> logger) : base(batchSize, logger) { ServiceScopeFactory = serviceScopeFactory; ServiceScope = ServiceScopeFactory.CreateScope(); _maxDegreeOfParallelism = masMaxDegreeOfParallelism; _singleActiveConsumer = singleActiveConsumer; _messageConsumer = ServiceScope.GetRequiredService <IMessageConsumer>(); QueueName = queueName; }
protected void InvokePerform(IJobPublisher publisher, IMessageReceiver receiver, JobInfo jobInfo, ulong deliveryTag, IJobServiceScope serviceScope, CancellationToken cancellationToken) { IBrokerTransaction tx = null; try { var reflectionInfo = ReflectionUtilities.ReflectionCache.GetJobReflectionInfo(jobInfo.JobType, jobInfo.ArgsType); object job; switch (reflectionInfo.CtorType) { case ReflectionUtilities.ConstructorType.NoArgs: job = reflectionInfo.Ctor.Invoke(null); break; case ReflectionUtilities.ConstructorType.NeedsPublisher: job = reflectionInfo.Ctor.Invoke(new object[] { publisher }); break; default: var parametersInfo = reflectionInfo.Ctor.GetParameters(); var parameters = new object[parametersInfo.Length]; for (var i = 0; i < parametersInfo.Length; i++) { if (parametersInfo[i].IsOut) { throw new Exception("Out parameters are not supported."); } parameters[i] = serviceScope.GetRequiredService(parametersInfo[i].ParameterType); } job = reflectionInfo.Ctor.Invoke(parameters); break; } if (job == null) { throw new Exception($"Job type {jobInfo.JobType} is not registered in service scope and appropriate constructor does not exist!"); } if ((bool)reflectionInfo.UseTransactionGetter(job)) { tx = receiver.BeginTransaction(serviceScope); } object result; switch (reflectionInfo.PerfMethodType) { case ReflectionUtilities.PerformMethodType.NoArgs: result = reflectionInfo.PerformDelegate1(job); break; case ReflectionUtilities.PerformMethodType.NeedsArgs: result = reflectionInfo.PerformDelegate2(job, jobInfo.Args); break; case ReflectionUtilities.PerformMethodType.NeedsCancellationToken: result = reflectionInfo.PerformDelegate3(job, cancellationToken); break; case ReflectionUtilities.PerformMethodType.NeedsArgsAndCancellationToken: result = reflectionInfo.PerformDelegate4(job, jobInfo.Args, cancellationToken); break; default: throw new ArgumentOutOfRangeException(nameof(reflectionInfo.PerfMethodType)); } if (result != null && result is Task taskResult) { taskResult.Wait(cancellationToken); } receiver.AckBatchMessageProcessed(serviceScope, deliveryTag); tx?.Commit(); } catch (TargetInvocationException ex) { try { tx?.Rollback(); } catch (Exception rollbackEx) { _logger.LogError(rollbackEx, "Rollback failed"); } if (ex.InnerException == null) { throw; } ExceptionDispatchInfo.Capture(ex.InnerException).Throw(); } finally { tx.SafeDispose(_logger); } }