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)); }
public async Task Store(OutboxItem outboxItem) { var json = JsonConvert.SerializeObject(outboxItem, settings); await using var stream = new MemoryStream(); await using var writer = new StreamWriter(stream); writer.Write(json); writer.Flush(); stream.Position = 0; var response = await container.UpsertItemStreamAsync(stream, PartitionKey.None); // HINT: Outbox item should be created or re-updated (if there was a failure // during previous commit). if (response.StatusCode != HttpStatusCode.Created && response.StatusCode != HttpStatusCode.OK) { throw new Exception("Error storing outbox item"); } }
public async Task Store(OutboxItem outboxItem, CancellationToken cancellationToken = default) { // ReSharper disable once UseAwaitUsing using var stream = MemoryStreamManager.GetStream(); // ReSharper disable once UseAwaitUsing using var streamWriter = new StreamWriter(stream); using var writer = new JsonTextWriter(streamWriter); serializer.Serialize(writer, outboxItem); await streamWriter.FlushAsync().ConfigureAwait(false); stream.Position = 0; var response = await container.UpsertItemStreamAsync(stream, PartitionKey.None, cancellationToken : cancellationToken); // HINT: Outbox item should be created or re-updated (if there was a failure // during previous commit). if (response.StatusCode != HttpStatusCode.Created && response.StatusCode != HttpStatusCode.OK) { throw new Exception("Error storing outbox item"); } }