private async Task ProcessQueueItemsAsync()
        {
            await this.controlQueueLock.WaitAsync();

            IDatabase database = this.redisConnection.GetDatabase();

            RedisValue[] messagesJson = await database.ListRangeAsync(this.partitionControlQueueKey);

            foreach (string messageJson in messagesJson)
            {
                TaskMessage taskMessage = RedisSerializer.DeserializeObject <TaskMessage>(messageJson);
                string      instanceId  = taskMessage.OrchestrationInstance.InstanceId;

                string orchestrationStateKey         = RedisKeyNameResolver.GetOrchestrationRuntimeStateHashKey(this.taskHub, this.partition);
                string orchestrationInstanceQueueKey = RedisKeyNameResolver.GetOrchestrationQueueKey(this.taskHub, this.partition, instanceId);

                // Enter empty runtime state if it is an execution start event
                if (taskMessage.Event is ExecutionStartedEvent startedEvent)
                {
                    OrchestrationRuntimeState emptyState = GetEmptyState(taskMessage);
                    await database.HashSetAsync(orchestrationStateKey, instanceId, RedisSerializer.SerializeObject(emptyState.Events), When.NotExists);
                }

                await database.ListRightPopLeftPushAsync(this.partitionControlQueueKey, orchestrationInstanceQueueKey);

                this.activeOrchestrationLocks.TryAdd(instanceId, new SemaphoreSlim(1, 1));
            }

            //Release lock so another notification can be handled
            this.controlQueueLock.Release();
        }
        public RedisTransactionBuilder RemoveTaskMessageFromActivityQueue(TaskMessage message, string workerId)
        {
            string activityProcessingQueueKey = RedisKeyNameResolver.GetTaskActivityProcessingQueueKey(this.taskHub, workerId);
            string messageJson = RedisSerializer.SerializeObject(message);

            transaction.ListRemoveAsync(activityProcessingQueueKey, messageJson);
            return(this);
        }
        public RedisTransactionBuilder SendActivityMessage(TaskMessage message)
        {
            string activityIncomingQueueKey = RedisKeyNameResolver.GetTaskActivityIncomingQueueKey(this.taskHub);
            string messageJson = RedisSerializer.SerializeObject(message);

            transaction.ListLeftPushAsync(activityIncomingQueueKey, messageJson);
            return(this);
        }
 /// <inheritdoc />
 public async Task AbandonTaskActivityWorkItemAsync(TaskActivityWorkItem workItem)
 {
     if (this.activityTaskManager == null)
     {
         await StartAsync();
     }
     IDatabase redisDb = this.redisConnection.GetDatabase();
     string    activityProcessingQueueKey = RedisKeyNameResolver.GetTaskActivityProcessingQueueKey(this.settings.TaskHubName, this.workerGuid);
     string    messageJson = RedisSerializer.SerializeObject(workItem.TaskMessage);
     await redisDb.ListRemoveAsync(activityProcessingQueueKey, messageJson);
 }
        public RedisTransactionBuilder AddOrchestrationStateToHistory(string orchestrationId, OrchestrationState state)
        {
            if (this.partition == null)
            {
                throw new ArgumentNullException($"Cannot call {nameof(AddOrchestrationStateToHistory)} without a partition set.");
            }
            string orchestrationStateKey = RedisKeyNameResolver.GetOrchestrationStateKey(this.taskHub, this.partition, orchestrationId);
            string stateJson             = RedisSerializer.SerializeObject(state);

            // Add to front of list so history in latest to oldest order
            transaction.StringSetAsync(orchestrationStateKey, stateJson);
            return(this);
        }
        public RedisTransactionBuilder SendControlQueueMessage(TaskMessage message)
        {
            if (this.partition == null)
            {
                throw new ArgumentNullException($"Cannot call {nameof(SendControlQueueMessage)} without a partition set.");
            }
            string controlQueueKey = RedisKeyNameResolver.GetPartitionControlQueueKey(this.taskHub, this.partition);
            string controlQueueNotificationChannelKey = RedisKeyNameResolver.GetPartitionControlNotificationChannelKey(this.taskHub, this.partition);
            string messageJson = RedisSerializer.SerializeObject(message);

            this.transaction.ListLeftPushAsync(controlQueueKey, messageJson);
            this.transaction.PublishAsync(new RedisChannel(controlQueueNotificationChannelKey, RedisChannel.PatternMode.Literal), messageJson);
            return(this);
        }
        public RedisTransactionBuilder SetOrchestrationRuntimeState(string orchestrationId, OrchestrationRuntimeState state)
        {
            if (this.partition == null)
            {
                throw new ArgumentNullException($"Cannot call {nameof(SetOrchestrationRuntimeState)} without a partition set.");
            }
            string orchestrationStateKey = RedisKeyNameResolver.GetOrchestrationRuntimeStateHashKey(this.taskHub, this.partition);

            // Do not want to serialize new events;
            state.NewEvents.Clear();
            string stateJson = RedisSerializer.SerializeObject(state.Events);

            transaction.HashSetAsync(orchestrationStateKey, orchestrationId, stateJson);
            return(this);
        }
        public async Task SendOrchestrationMessages(params TaskMessage[] messages)
        {
            IDatabase redisDb = this.redisConnection.GetDatabase();

            Task[]       sendMessageTasks    = new Task[messages.Length];
            RedisChannel notificationChannel = new RedisChannel(this.partitionControlQueueNotificationChannelKey, RedisChannel.PatternMode.Literal);

            for (int i = 0; i < messages.Length; i++)
            {
                string messageJson = RedisSerializer.SerializeObject(messages[i]);
                sendMessageTasks[i] = redisDb.ListLeftPushAsync(this.partitionControlQueueKey, messageJson);
            }
            await Task.WhenAll(sendMessageTasks);

            await redisDb.PublishAsync(notificationChannel, "batch received");
        }