public override async Task CompleteTaskActivityWorkItemAsync(TaskActivityWorkItem workItem, TaskMessage responseMessage)
        {
            using SqlConnection connection = await this.GetAndOpenConnectionAsync();

            using SqlCommand command = this.GetSprocCommand(connection, "dt._CompleteTasks");

            command.Parameters.AddMessageIdParameter("@CompletedTasks", workItem.TaskMessage);
            command.Parameters.AddTaskEventsParameter("@Results", responseMessage);

            OrchestrationInstance instance = workItem.TaskMessage.OrchestrationInstance;

            try
            {
                await SqlUtils.ExecuteNonQueryAsync(command, this.traceHelper, instance.InstanceId);
            }
            catch (SqlException e) when(e.Number == 50002)
            {
                // 50002 is the error code when we fail to delete the source message. This is expected to mean that
                // a task activity has executed twice, likely because of an unexpected lock expiration.
                string taskName = DTUtils.GetName(workItem.TaskMessage.Event) ?? "Unknown";

                this.traceHelper.DuplicateExecutionDetected(instance, taskName);
                return;
            }

            // signal the orchestration loop to poll immediately
            this.orchestrationBackoffHelper.Reset();
        }
        public override async Task <TaskActivityWorkItem?> LockNextTaskActivityWorkItem(TimeSpan receiveTimeout, CancellationToken cancellationToken)
        {
            while (!cancellationToken.IsCancellationRequested)
            {
                using SqlConnection connection = await this.GetAndOpenConnectionAsync();

                using SqlCommand command = this.GetSprocCommand(connection, "dt._LockNextTask");

                DateTime lockExpiration = DateTime.UtcNow.Add(this.settings.WorkItemLockTimeout);

                command.Parameters.Add("@LockedBy", SqlDbType.VarChar, size: 100).Value = this.lockedByValue;
                command.Parameters.Add("@LockExpiration", SqlDbType.DateTime2).Value    = lockExpiration;

                using DbDataReader reader = await SqlUtils.ExecuteReaderAsync(
                          command,
                          this.traceHelper,
                          instanceId : null,
                          cancellationToken);

                if (!await reader.ReadAsync())
                {
                    await this.activityBackoffHelper.WaitAsync(cancellationToken);

                    continue;
                }

                this.activityBackoffHelper.Reset();

                TaskMessage message      = reader.GetTaskMessage();
                int         dequeueCount = reader.GetInt32("DequeueCount");

                // TODO: poison message handling for high dequeue counts

                return(new TaskActivityWorkItem
                {
                    Id = $"{message.OrchestrationInstance.InstanceId}:{DTUtils.GetTaskEventId(message.Event):X16}",
                    TaskMessage = message,
                    LockedUntilUtc = lockExpiration,
                });
            }

            // host is shutting down
            return(null);
        }