private async Task AssertTableHasExpectedColumnsAsync(QueuedTaskMapping mapping)
        {
            bool tableHasColumns = await TableHasColumnsAsync(mapping.ResultsQueueTableName,
                                                              QueueResultTableDbAssetSetup.TaskIdColumnName,
                                                              QueueResultTableDbAssetSetup.TaskTypeColumnName,
                                                              QueueResultTableDbAssetSetup.TaskStatusColumnName,
                                                              QueueResultTableDbAssetSetup.TaskSourceColumnName,
                                                              QueueResultTableDbAssetSetup.TaskPayloadColumnName,
                                                              QueueResultTableDbAssetSetup.TaskPriorityColumnName,
                                                              QueueResultTableDbAssetSetup.TaskLastErrorColumnName,
                                                              QueueResultTableDbAssetSetup.TaskErrorCountColumnName,
                                                              QueueResultTableDbAssetSetup.TaskLastErrorIsRecoverableColumnName,
                                                              QueueResultTableDbAssetSetup.TaskProcessingTimeMillisecondsColumnName,
                                                              QueueResultTableDbAssetSetup.TaskPostedAtColumnName,
                                                              QueueResultTableDbAssetSetup.TaskFirstProcessingAttemptedAtColumnName,
                                                              QueueResultTableDbAssetSetup.TaskLastProcessingAttemptedAtColumnName,
                                                              QueueResultTableDbAssetSetup.TaskProcessingFinalizedAtColumnName);

            Assert.IsTrue(tableHasColumns,
                          "Table {0} does not have all expected columns!",
                          mapping.ResultsQueueTableName);
        }
예제 #2
0
        private string GetDequeueFunctionCreationScript(QueuedTaskMapping mapping)
        {
            return($@"CREATE OR REPLACE FUNCTION public.{mapping.DequeueFunctionName}(
					{SelectTypesParamName} character varying[],
					{ExcludeIdsParamName} uuid[],
					{RefNowParamName} timestamp with time zone)
				RETURNS TABLE({TaskIdTableParamName} uuid, 
					{TaskLockHandleIdTableParamName} bigint, 
					{TaskTypeTableParamName} character varying, 
					{TaskSourceTableParamName} character varying, 
					{TaskPayloadTableParamName} text, 
					{TaskPriorityTableParamName} integer, 
					{TaskPostedAtTableParamName} timestamp with time zone, 
					{TaskLockedUntilTableParamName} timestamp with time zone) 
				LANGUAGE 'plpgsql'

			AS $BODY$
				DECLARE
					n_select_types integer = CARDINALITY({SelectTypesParamName});
	
				BEGIN
					RETURN QUERY 
					WITH sk_dequeued_task AS
						(DELETE FROM {mapping.QueueTableName} td WHERE td.task_id = (
							SELECT t0.task_id
									FROM {mapping.QueueTableName} t0 
									WHERE (t0.task_type = ANY({SelectTypesParamName}) OR n_select_types = 0)
										AND t0.task_locked_until_ts < {RefNowParamName}
										AND t0.task_id <> ALL({ExcludeIdsParamName})
									ORDER BY t0.task_priority ASC,
										t0.task_locked_until_ts ASC,
										t0.task_lock_handle_id ASC
									LIMIT 1
									FOR UPDATE SKIP LOCKED
						) RETURNING *) SELECT sdt.* FROM sk_dequeued_task sdt;
				END;
			$BODY$;"            );
        }
예제 #3
0
        private StakhanoviseSetupDefaults MergeDefaultsFromConfig(StakhanoviseSetupDefaults targetDefaults,
                                                                  StakhanoviseSetupDefaultsConfig defaultsConfig,
                                                                  IConfiguration config)
        {
            ScriptOptions parseOptions = ConstructParseOptions();

            Assembly[] executorAssemblies = ParseExecutorAssembliesFromConfig(defaultsConfig);
            if (executorAssemblies != null)
            {
                targetDefaults.ExecutorAssemblies = executorAssemblies;
            }

            Func <IQueuedTaskToken, long> calculateDelayTicksTaskAfterFailureFn =
                CompileCalculateDelayTicksTaskAfterFailureFnFromConfig(defaultsConfig, parseOptions);

            if (calculateDelayTicksTaskAfterFailureFn != null)
            {
                targetDefaults.CalculateDelayMillisecondsTaskAfterFailure = calculateDelayTicksTaskAfterFailureFn;
            }

            Func <IQueuedTask, Exception, bool> isTaskErrorRecoverableFn =
                CompileIsTaskErrorRecoverableFnFromConfig(defaultsConfig, parseOptions);

            if (isTaskErrorRecoverableFn != null)
            {
                targetDefaults.IsTaskErrorRecoverable = isTaskErrorRecoverableFn;
            }

            if (!string.IsNullOrWhiteSpace(defaultsConfig.ConnectionStringName))
            {
                targetDefaults.ConnectionString = config.GetConnectionString(defaultsConfig.ConnectionStringName);
            }

            QueuedTaskMapping mappingFromConfig =
                GetQueudTaskMappingFromDefaultsConfig(defaultsConfig);

            targetDefaults.Mapping = MergeMappingFromConfig(targetDefaults.Mapping,
                                                            mappingFromConfig);

            if (defaultsConfig.WorkerCount > 0)
            {
                targetDefaults.WorkerCount = defaultsConfig.WorkerCount;
            }

            if (defaultsConfig.FaultErrorThresholdCount > 0)
            {
                targetDefaults.FaultErrorThresholdCount = defaultsConfig.FaultErrorThresholdCount;
            }

            if (defaultsConfig.AppMetricsCollectionIntervalMilliseconds > 0)
            {
                targetDefaults.AppMetricsCollectionIntervalMilliseconds = defaultsConfig.AppMetricsCollectionIntervalMilliseconds;
            }

            if (defaultsConfig.AppMetricsMonitoringEnabled.HasValue)
            {
                targetDefaults.AppMetricsMonitoringEnabled = defaultsConfig.AppMetricsMonitoringEnabled.Value;
            }

            if (defaultsConfig.SetupBuiltInDbAsssets.HasValue)
            {
                targetDefaults.SetupBuiltInDbAsssets = defaultsConfig.SetupBuiltInDbAsssets.Value;
            }

            return(targetDefaults);
        }
예제 #4
0
        public async Task Test_CanCreateDequeueFunction_WithNonDefaultMapping()
        {
            QueuedTaskMapping mapping = GenerateNonDefaultMapping();

            await RunDbAssetSetupTestsAsync(mapping);
        }
예제 #5
0
 public NpgsqlDataReaderExtensionsTests()
 {
     mMapping    = TestOptions.DefaultMapping;
     mOperations = new PostgreSqlTaskQueueDbOperations(ConnectionString, mMapping);
 }
 public PostgreSqlAppMetricsMonitorWriterOptions(ConnectionOptions connectionOptions, QueuedTaskMapping mapping)
 {
     ConnectionOptions = connectionOptions
                         ?? throw new ArgumentNullException(nameof(connectionOptions));
     Mapping = mapping
               ?? throw new ArgumentNullException(nameof(mapping));
 }
예제 #7
0
        private Mock <ISetupDbAsset> CreateDbAssetSetupMockWithoutError(ConnectionOptions connectionOptions, QueuedTaskMapping mapping)
        {
            Mock <ISetupDbAsset> dbAssetMock = new Mock <ISetupDbAsset>();

            dbAssetMock.Setup(m => m.SetupDbAssetAsync(connectionOptions, mapping))
            .Returns(Task.CompletedTask)
            .Verifiable();

            return(dbAssetMock);
        }
        public async Task SetupDbAssetAsync(ConnectionOptions queueConnectionOptions, QueuedTaskMapping mapping)
        {
            if (queueConnectionOptions == null)
            {
                throw new ArgumentNullException(nameof(queueConnectionOptions));
            }
            if (mapping == null)
            {
                throw new ArgumentNullException(nameof(mapping));
            }

            using (NpgsqlConnection conn = await queueConnectionOptions.TryOpenConnectionAsync())
            {
                using (NpgsqlCommand cmdTable = new NpgsqlCommand(GetDbTableCreationScript(mapping), conn))
                    await cmdTable.ExecuteNonQueryAsync();
            }
        }
예제 #9
0
 public TaskQueueInfoOptions(ConnectionOptions connectionOptions,
                             QueuedTaskMapping mapping)
     : base(connectionOptions, mapping)
 {
     return;
 }
예제 #10
0
 public Program()
 {
     mMapping       = new QueuedTaskMapping();
     mConfiguration = GetConfig();
 }
        private string GetTaskAcquireSql(QueuedTaskMapping mapping)
        {
            return($@"DELETE FROM {mapping.QueueTableName} 
				WHERE task_id = @t_id"                );
        }
 private string GetTaskDequeueSql(QueuedTaskMapping mapping)
 {
     //See https://dba.stackexchange.com/questions/69471/postgres-update-limit-1/69497#69497
     return($@"SELECT tq.* FROM { mapping.DequeueFunctionName }(@types, @excluded, @ref_now) tq");
 }
예제 #13
0
        public StakhanoviseSetup(StakhanoviseSetupDefaults defaults)
        {
            if (defaults == null)
            {
                throw new ArgumentNullException(nameof(defaults));
            }

            mMapping = defaults.Mapping;

            mSetupBuiltInDbAsssets = defaults
                                     .SetupBuiltInDbAsssets;

            mAppMetricsMonitoringEnabled = defaults
                                           .AppMetricsMonitoringEnabled;

            StandardConnectionSetup queueConsumerConnectionSetup =
                new StandardConnectionSetup(defaults);

            StandardConnectionSetup queueProducerConnectionSetup =
                new StandardConnectionSetup(defaults);

            StandardConnectionSetup queueInfoConnectionSetup =
                new StandardConnectionSetup(defaults);

            StandardConnectionSetup builtInTimingBeltConnectionSetup =
                new StandardConnectionSetup(defaults);

            StandardConnectionSetup builtInWriterConnectionSetup =
                new StandardConnectionSetup(defaults);

            StandardConnectionSetup builtInAppMetricsWriterConnectionSetup =
                new StandardConnectionSetup(defaults);

            mSetupDbAssetsConnectionSetup =
                new StandardConnectionSetup(defaults);

            mTaskQueueProducerSetup = new StandardTaskQueueProducerSetup(queueProducerConnectionSetup,
                                                                         defaults);

            mTaskQueueInfoSetup = new StandardTaskQueueInfoSetup(queueInfoConnectionSetup,
                                                                 defaults);

            mCommonTaskQueueConnectionSetup = new CollectiveConnectionSetup(queueConsumerConnectionSetup,
                                                                            queueProducerConnectionSetup,
                                                                            queueInfoConnectionSetup,
                                                                            builtInTimingBeltConnectionSetup,
                                                                            builtInWriterConnectionSetup,
                                                                            builtInAppMetricsWriterConnectionSetup,
                                                                            mSetupDbAssetsConnectionSetup);

            mTaskQueueConsumerSetup = new StandardTaskQueueConsumerSetup(queueConsumerConnectionSetup,
                                                                         defaults);

            mTaskEngineSetup = new StandardTaskEngineSetup(mTaskQueueConsumerSetup,
                                                           defaults);

            mPerformanceMonitorWriterSetup = new StandardExecutionPerformanceMonitorWriterSetup(builtInWriterConnectionSetup,
                                                                                                defaults);

            mAppMetricsMonitorSetup = new StandardAppMetricsMonitorSetup(defaults);

            mAppMetricsMonitorWriterSetup = new StandardAppMetricsMonitorWriterSetup(builtInAppMetricsWriterConnectionSetup,
                                                                                     defaults);
        }
예제 #14
0
        private async Task RunDbAssetFactoryTests(ConnectionOptions connectionOptions, QueuedTaskMapping mapping, int count)
        {
            List <Mock <ISetupDbAsset> > dbAssetSetupsMocks = CreateDbAssetSetupMocksWithoutError(connectionOptions,
                                                                                                  mapping,
                                                                                                  count);

            IList <ISetupDbAsset> dbAssetSetups = dbAssetSetupsMocks
                                                  .Select(m => m.Object)
                                                  .ToList();

            DbAssetFactory factory = new DbAssetFactory(dbAssetSetups,
                                                        connectionOptions,
                                                        mapping);

            await factory.CreateDbAssetsAsync();

            foreach (Mock <ISetupDbAsset> mock in dbAssetSetupsMocks)
            {
                mock.Verify();
                mock.VerifyNoOtherCalls();
            }
        }
예제 #15
0
        private QueuedTaskMapping MergeMappingFromConfig(QueuedTaskMapping targeMapping, QueuedTaskMapping mappingFromConfig)
        {
            if (!string.IsNullOrWhiteSpace(mappingFromConfig.DequeueFunctionName))
            {
                targeMapping.DequeueFunctionName = mappingFromConfig.DequeueFunctionName;
            }
            if (!string.IsNullOrWhiteSpace(mappingFromConfig.ExecutionTimeStatsTableName))
            {
                targeMapping.ExecutionTimeStatsTableName = mappingFromConfig.ExecutionTimeStatsTableName;
            }
            if (!string.IsNullOrWhiteSpace(mappingFromConfig.MetricsTableName))
            {
                targeMapping.MetricsTableName = mappingFromConfig.MetricsTableName;
            }
            if (!string.IsNullOrWhiteSpace(mappingFromConfig.NewTaskNotificationChannelName))
            {
                targeMapping.NewTaskNotificationChannelName = mappingFromConfig.NewTaskNotificationChannelName;
            }
            if (!string.IsNullOrWhiteSpace(mappingFromConfig.QueueTableName))
            {
                targeMapping.QueueTableName = mappingFromConfig.QueueTableName;
            }
            if (!string.IsNullOrWhiteSpace(mappingFromConfig.ResultsQueueTableName))
            {
                targeMapping.ResultsQueueTableName = mappingFromConfig.ResultsQueueTableName;
            }

            return(targeMapping);
        }
        public async Task SetupDbAssetAsync(ConnectionOptions queueConnectionOptions, QueuedTaskMapping mapping)
        {
            if (queueConnectionOptions == null)
            {
                throw new ArgumentNullException(nameof(queueConnectionOptions));
            }
            if (mapping == null)
            {
                throw new ArgumentNullException(nameof(mapping));
            }

            using (NpgsqlConnection conn = await queueConnectionOptions.TryOpenConnectionAsync())
            {
                using (NpgsqlCommand cmdLockHandleIdSeq = new NpgsqlCommand(GetLockHandleIdSequenceCreationScript(mapping),
                                                                            conn))
                    await cmdLockHandleIdSeq.ExecuteNonQueryAsync();

                using (NpgsqlCommand cmdTable = new NpgsqlCommand(GetDbTableCreationScript(mapping),
                                                                  conn))
                    await cmdTable.ExecuteNonQueryAsync();

                if (mCreateSortIndex)
                {
                    using (NpgsqlCommand cmdCreateSortIndex = new NpgsqlCommand(GetSortIndexCreationScript(mapping),
                                                                                conn))
                        await cmdCreateSortIndex.ExecuteNonQueryAsync();
                }

                if (mCreateFilterIndex)
                {
                    using (NpgsqlCommand cmdCreateFilterIndex = new NpgsqlCommand(GetFilterIndexCreationScript(mapping),
                                                                                  conn))
                        await cmdCreateFilterIndex.ExecuteNonQueryAsync();
                }
            }
        }
 public PostgreSqlTaskQueueDbOperations(string connectionString,
                                        QueuedTaskMapping mapping)
 {
     mConnectionString = connectionString;
     mMapping          = mapping;
 }
 private string GetLockHandleIdSequenceName(QueuedTaskMapping mapping)
 {
     return(string.Format(LockHandleIdSequenceNameFormat, mapping.QueueTableName));
 }
예제 #19
0
        public async Task Test_CanSetupDbAsset_WithNonDefaultMapping()
        {
            QueuedTaskMapping mapping = GenerateNonDefaultMapping();

            await RunDbAssetSetupTestsAsync(mapping);
        }
예제 #20
0
        private List <Mock <ISetupDbAsset> > CreateDbAssetSetupMocksWithoutError(ConnectionOptions connectionOptions, QueuedTaskMapping mapping, int count)
        {
            List <Mock <ISetupDbAsset> > dbAssetMocks = new List <Mock <ISetupDbAsset> >(count);

            for (int i = 0; i < count; i++)
            {
                dbAssetMocks.Add(CreateDbAssetSetupMockWithoutError(connectionOptions, mapping));
            }
            return(dbAssetMocks);
        }