Пример #1
0
        /// <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;
        }
Пример #3
0
        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));
        }
Пример #5
0
        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");
            }
        }
Пример #7
0
        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;
        }
Пример #8
0
        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);
            }
        }