public async Task <TSideEffect> Process <TState, TSideEffect>(string requestId, string stateId,
                                                                      Func <TState, TSideEffect> handle, CancellationToken cancellationToken = default) where TState : State, new()
        {
            var(state, version) = await stateStore.Load <TState>(stateId, cancellationToken)
                                  .ConfigureAwait(false);

            if (state.TxId != null)
            {
                await FinishTransaction(stateId, state, version, cancellationToken)
                .ConfigureAwait(false);
            }

            var outboxState = await outboxStore.Get(requestId, cancellationToken);

            if (outboxState != null)
            {
                return(JsonConvert.DeserializeObject <TSideEffect>(outboxState.SideEffect));
            }

            var sideEffect = handle(state);

            state.TxId = Guid.NewGuid();

            outboxState = new OutboxItem
            {
                Id         = state.TxId.ToString(),
                RequestId  = requestId,
                SideEffect = JsonConvert.SerializeObject(sideEffect)
            };

            await outboxStore.Store(outboxState, cancellationToken)
            .ConfigureAwait(false);

            string nextVersion;

            try
            {
                nextVersion = await stateStore.Upsert(stateId, state, version, cancellationToken)
                              .ConfigureAwait(false);
            }
            catch (Exception e) when(!(e is OperationCanceledException))
            {
                await outboxStore.Delete(outboxState.Id, cancellationToken)
                .ConfigureAwait(false);

                throw;
            }

            await FinishTransaction(stateId, state, nextVersion, cancellationToken)
            .ConfigureAwait(false);

            return(sideEffect);
        }
        public async Task <TSideEffect> Process <TState, TSideEffect>(string requestId, string stateId,
                                                                      Func <TState, TSideEffect> handle) where TState : State, new()
        {
            var(state, version) = await stateStore.Load <TState>(stateId);

            if (state.TxId != null)
            {
                await FinishTransaction(stateId, state, version);
            }

            var outboxState = await outboxStore.Get(requestId);

            if (outboxState == null)
            {
                var sideEffect = handle(state);

                state.TxId = Guid.NewGuid();

                outboxState = new OutboxItem
                {
                    Id         = state.TxId.ToString(),
                    RequestId  = requestId,
                    SideEffect = JsonConvert.SerializeObject(sideEffect)
                };

                await outboxStore.Store(outboxState);

                string nextVersion;

                try
                {
                    nextVersion = await stateStore.Upsert(stateId, state, version);
                }
                catch
                {
                    await outboxStore.Delete(outboxState.Id);

                    throw;
                }

                await FinishTransaction(stateId, state, nextVersion);

                return(sideEffect);
            }

            return(JsonConvert.DeserializeObject <TSideEffect>(outboxState.SideEffect));
        }