public Task Store(OutboxMessage message, OutboxTransaction transaction, ContextBag context) { var session = ((RavenDBOutboxTransaction)transaction).AsyncSession; var operations = new OutboxRecord.OutboxOperation[message.TransportOperations.Length]; var index = 0; foreach (var transportOperation in message.TransportOperations) { operations[index] = new OutboxRecord.OutboxOperation { Message = transportOperation.Body, Headers = transportOperation.Headers, MessageId = transportOperation.MessageId, Options = transportOperation.Options }; index++; } return session.StoreAsync(new OutboxRecord { MessageId = message.MessageId, Dispatched = false, TransportOperations = operations }, GetOutboxRecordId(message.MessageId)); }
public async Task Should_return_the_next_time_of_retrieval() { query.CleanupGapFromTimeslice = TimeSpan.FromSeconds(1); query.TriggerCleanupEvery = TimeSpan.Zero; var nextTime = DateTime.UtcNow.AddHours(1); var context = new ContextBag(); await persister.Add(new TimeoutData { Time = nextTime, Destination = "timeouts@" + RuntimeEnvironment.MachineName, SagaId = Guid.NewGuid(), State = new byte[] { 0, 0, 133 }, Headers = new Dictionary<string, string> { {"Bar", "34234"}, {"Foo", "aString1"}, {"Super", "aString2"} }, OwningTimeoutManager = "MyTestEndpoint" }, context); WaitForIndexing(store); var nextTimeToRunQuery = (await query.GetNextChunk(DateTime.UtcNow.AddYears(-3))).NextTimeToQuery; Assert.IsTrue((nextTime - nextTimeToRunQuery).TotalSeconds < 1); }
public async Task<OutboxTransaction> BeginTransaction(ContextBag context) { var connection = connectionBuilder(); await connection.OpenAsync(); var transaction = connection.BeginTransaction(); return new SqlOutboxTransaction(transaction, connection); }
public static ContextBag CreateContextWithAsyncSessionPresent(this RavenDBPersistenceTestBase testBase, out IAsyncDocumentSession session) { var context = new ContextBag(); session = testBase.OpenAsyncSession(); context.Set(session); return context; }
public async Task<CompletableSynchronizedStorageSession> OpenSession(ContextBag contextBag) { var connection = connectionBuilder(); await connection.OpenAsync(); var transaction = connection.BeginTransaction(); return new StorageSession(connection, transaction,true); }
public async Task<OutboxMessage> Get(string messageId, ContextBag options) { OutboxRecord result; using (var session = documentStore.OpenAsyncSession()) { session.Advanced.AllowNonAuthoritativeInformation = false; // We use Load operation and not queries to avoid stale results var possibleIds = GetPossibleOutboxDocumentIds(messageId); var docs = await session.LoadAsync<OutboxRecord>(possibleIds).ConfigureAwait(false); result = docs.FirstOrDefault(o => o != null); } if (result == null) { return default(OutboxMessage); } if (result.Dispatched || result.TransportOperations.Length == 0) { return new OutboxMessage(result.MessageId, emptyTransportOperations); } var transportOperations = new TransportOperation[result.TransportOperations.Length]; var index = 0; foreach (var op in result.TransportOperations) { transportOperations[index] = new TransportOperation(op.MessageId, op.Options, op.Message, op.Headers); index++; } return new OutboxMessage(result.MessageId, transportOperations); }
public async Task It_should_successfully_remove_the_saga() { var id = Guid.NewGuid(); var sagaData = new SagaWithoutUniquePropertyData { Id = id, NonUniqueString = "whatever" }; var persister = new InMemorySagaPersister(); var savingSession = new InMemorySynchronizedStorageSession(); await persister.Save(sagaData, null, savingSession, new ContextBag()); await savingSession.CompleteAsync(); // second session var completingSession = new InMemorySynchronizedStorageSession(); var completingContextBag = new ContextBag(); var saga = await persister.Get<SagaWithoutUniquePropertyData>(id, completingSession, completingContextBag); await persister.Complete(saga, completingSession, completingContextBag); await completingSession.CompleteAsync(); var result = await persister.Get<SagaWithoutUniquePropertyData>(sagaData.Id, savingSession, new ContextBag()); Assert.That(result, Is.Null); }
public async Task<TimeoutData> Peek(string timeoutId, ContextBag context) { using (var connection = connectionBuilder()) { await connection.OpenAsync(); using (var command = connection.CreateCommand()) { command.CommandText = timeoutCommands.Peek; command.AddParameter("Id", timeoutId); using (var reader = await command.ExecuteReaderAsync(CommandBehavior.SingleRow)) { if (!await reader.ReadAsync()) { return null; } var headers = ReadHeaders(reader); return new TimeoutData { Id = timeoutId, Destination = reader.GetString(0), SagaId = reader.GetGuid(1), State = (byte[]) reader.GetValue(2), Time = reader.GetDateTime(3), Headers = headers, }; } } } }
public async Task<bool> DeduplicateMessage(string messageId, DateTime timeReceived, ContextBag context) { using (var session = documentStore.OpenAsyncSession()) { session.Advanced.UseOptimisticConcurrency = true; session.Advanced.AllowNonAuthoritativeInformation = false; await session.StoreAsync(new GatewayMessage { Id = EscapeMessageId(messageId), TimeReceived = timeReceived }).ConfigureAwait(false); try { await session.SaveChangesAsync().ConfigureAwait(false); } catch (ConcurrencyException) { return false; } return true; } }
public async Task Save_fails_when_data_changes_between_read_and_update_on_same_thread() { var sagaId = Guid.NewGuid(); var saga = new TestSagaData { Id = sagaId, SomeId = sagaId.ToString() }; var persister = new InMemorySagaPersister(); var insertSession = new InMemorySynchronizedStorageSession(); await persister.Save(saga, SagaMetadataHelper.GetMetadata<TestSaga>(saga), insertSession, new ContextBag()); await insertSession.CompleteAsync(); var winningContext = new ContextBag(); var record = await persister.Get<TestSagaData>(saga.Id, new InMemorySynchronizedStorageSession(), winningContext); var losingContext = new ContextBag(); var staleRecord = await persister.Get<TestSagaData>("SomeId", sagaId.ToString(), new InMemorySynchronizedStorageSession(), losingContext); var winningSaveSession = new InMemorySynchronizedStorageSession(); var losingSaveSession = new InMemorySynchronizedStorageSession(); await persister.Update(record, winningSaveSession, winningContext); await persister.Update(staleRecord, losingSaveSession, losingContext); await winningSaveSession.CompleteAsync(); Assert.That(async () => await losingSaveSession.CompleteAsync(), Throws.InstanceOf<Exception>().And.Message.StartsWith($"InMemorySagaPersister concurrency violation: saga entity Id[{saga.Id}] already saved.")); }
public void EnsureMappingFailsWithoutIndex() { var context = new ContextBag(); using (var db = new ReusableDB()) { using (var store = db.NewStore()) { ApplyTestConventions(store, ConventionType.RavenDefault); store.Initialize(); // Remove the index to make sure the conventions will throw store.DatabaseCommands.DeleteIndex("Raven/DocumentsByEntityName"); var persister = new TimeoutPersister(store); var exception = Assert.Throws<AggregateException>(() => { persister.Add(new TimeoutData { Destination = EndpointName, Headers = new Dictionary<string, string>(), OwningTimeoutManager = EndpointName, SagaId = Guid.NewGuid(), Time = DateTime.UtcNow }, context).Wait(); }); Assert.IsInstanceOf<InvalidOperationException>(exception.GetBaseException()); Console.WriteLine($"Got expected Exception: {exception.Message}"); } } }
public async Task It_should_successfully_update_the_saga() { var id = Guid.NewGuid(); var sagaData = new SagaWithoutUniquePropertyData { Id = id, NonUniqueString = "whatever" }; var persister = new InMemorySagaPersister(); // first session var session = new InMemorySynchronizedStorageSession(); await persister.Save(sagaData, SagaCorrelationProperty.None, session, new ContextBag()); await session.CompleteAsync(); // second session var session2 = new InMemorySynchronizedStorageSession(); var ctx = new ContextBag(); var saga = await persister.Get<SagaWithoutUniquePropertyData>(id, session2, ctx); saga.NonUniqueString = "asdfasdf"; await persister.Update(saga, session2, ctx); await session2.CompleteAsync(); var result = await persister.Get<SagaWithoutUniquePropertyData>(sagaData.Id, new InMemorySynchronizedStorageSession(), new ContextBag()); Assert.That(result, Is.Not.Null); Assert.That(result.NonUniqueString, Is.EqualTo("asdfasdf")); }
public async Task Should_return_the_complete_list_of_timeouts() { const int numberOfTimeoutsToAdd = 10; var context = new ContextBag(); for (var i = 0; i < numberOfTimeoutsToAdd; i++) { await persister.Add(new TimeoutData { Time = DateTime.UtcNow.AddHours(-1), Destination = "timeouts@" + RuntimeEnvironment.MachineName, SagaId = Guid.NewGuid(), State = new byte[] { 0, 0, 133 }, Headers = new Dictionary<string, string> { {"Bar", "34234"}, {"Foo", "aString1"}, {"Super", "aString2"} }, OwningTimeoutManager = "MyTestEndpoint" }, context); } WaitForIndexing(store); Assert.AreEqual(numberOfTimeoutsToAdd, (await query.GetNextChunk(DateTime.UtcNow.AddYears(-3))).DueTimeouts.Count()); }
public async Task Should_allow_old_timeouts_without_machine_name() { var headers = new Dictionary<string, string> { {"Bar", "34234"}, {"Foo", "aString1"}, {"Super", "aString2"} }; var timeout = new LegacyTimeoutData { Time = DateTime.UtcNow.AddHours(-1), Destination = new LegacyAddress("timeouts", null), SagaId = Guid.NewGuid(), State = new byte[] { 1, 1, 133, 200 }, Headers = headers, OwningTimeoutManager = "MyTestEndpoint" }; var context = new ContextBag(); var session = store.OpenAsyncSession(); await session.StoreAsync(timeout); await session.SaveChangesAsync(); Assert.True(await persister.TryRemove(timeout.Id, context)); }
public void EnsureMappingDocumentIsUsed() { var context = new ContextBag(); using (var db = new ReusableDB()) { for (var i = 0; i < 5; i++) { using (var store = db.NewStore()) { ApplyTestConventions(store, ConventionType.RavenDefault); store.Initialize(); if (i > 0) { // On every iteration after the first, remove the index so that operations // will throw if the mapping document does not exist. store.DatabaseCommands.DeleteIndex("Raven/DocumentsByEntityName"); } var persister = new TimeoutPersister(store); persister.Add(new TimeoutData { Destination = EndpointName, Headers = new Dictionary<string, string>(), OwningTimeoutManager = EndpointName, SagaId = Guid.NewGuid(), Time = DateTime.UtcNow }, context).Wait(); } } } }
public Task Subscribe(Subscriber subscriber, MessageType messageType, ContextBag context) { var dict = storage.GetOrAdd(messageType, type => new ConcurrentDictionary<string, Subscriber>(StringComparer.OrdinalIgnoreCase)); dict.AddOrUpdate(subscriber.TransportAddress, _ => subscriber, (_, __) => subscriber); return TaskEx.CompletedTask; }
public async Task Unsubscribe(Subscriber subscriber, MessageType messageType, ContextBag context) { using (var connection = connectionBuilder()) { await connection.OpenAsync(); await Unsubscribe(subscriber, connection, messageType); } }
public Task<IEnumerable<UnicastRoutingStrategy>> Route(Type messageType, IDistributionPolicy distributionPolicy, ContextBag contextBag) { IEnumerable<UnicastRoutingStrategy> unicastRoutingStrategies = new List<UnicastRoutingStrategy> { new UnicastRoutingStrategy("Fake") }; return Task.FromResult(unicastRoutingStrategies); }
public Task<TimeoutData> Peek(string timeoutId, ContextBag context) { ThrowExceptionUntilWaitTimeReached(); if (storage.ContainsKey(timeoutId)) { return Task.FromResult(storage[timeoutId]); } return Task.FromResult<TimeoutData>(null); }
async Task SaveSaga(SagaWithUniquePropertyData saga) { using (var session = new InMemorySynchronizedStorageSession()) { var ctx = new ContextBag(); await persister.Save(saga, SagaMetadataHelper.GetMetadata<SagaWithUniqueProperty>(saga), session, ctx); await session.CompleteAsync(); } }
public Task<OutboxMessage> Get(string messageId, ContextBag options) { if (ExistingMessage != null && ExistingMessage.MessageId == messageId) { return Task.FromResult(ExistingMessage); } return Task.FromResult(default(OutboxMessage)); }
public async Task Subscribe(Subscriber subscriber, MessageType messageType, ContextBag context) { //When the subscriber is running V6 and UseLegacyMessageDrivenSubscriptionMode is enabled at the subscriber the 'subcriber.Endpoint' value is null var endpoint = subscriber.Endpoint ?? subscriber.TransportAddress.Split('@').First(); var subscriptionClient = new SubscriptionClient { TransportAddress = subscriber.TransportAddress, Endpoint = endpoint }; var attempts = 0; //note: since we have a design that can run into concurrency exceptions we perform a few retries // we should redesign this in the future to use a separate doc per subscriber and message type do { try { using (var session = OpenAsyncSession()) { var subscriptionDocId = Subscription.FormatId(messageType); var subscription = await session.LoadAsync<Subscription>(subscriptionDocId).ConfigureAwait(false); if (subscription == null) { subscription = new Subscription { Id = subscriptionDocId, MessageType = messageType, Subscribers = new List<SubscriptionClient>() }; await session.StoreAsync(subscription).ConfigureAwait(false); } if (!subscription.Subscribers.Contains(subscriptionClient)) { subscription.Subscribers.Add(subscriptionClient); } else { var savedSubscription = subscription.Subscribers.Single(s => s.Equals(subscriptionClient)); if (savedSubscription.Endpoint != subscriber.Endpoint) { savedSubscription.Endpoint = subscriber.Endpoint; } } await session.SaveChangesAsync().ConfigureAwait(false); } return; } catch (ConcurrencyException) { attempts++; } } while (attempts < 5); }
public Task<CompletableSynchronizedStorageSession> TryAdapt(OutboxTransaction transaction, ContextBag context) { var inMemOutboxTransaction = transaction as InMemoryOutboxTransaction; if (inMemOutboxTransaction != null) { CompletableSynchronizedStorageSession session = new InMemorySynchronizedStorageSession(inMemOutboxTransaction.Transaction); return Task.FromResult(session); } return EmptyTask; }
public Task<CompletableSynchronizedStorageSession> TryAdapt(OutboxTransaction transaction, ContextBag context) { var ravenTransaction = transaction as RavenDBOutboxTransaction; if (ravenTransaction != null) { CompletableSynchronizedStorageSession session = new RavenDBSynchronizedStorageSession(ravenTransaction.AsyncSession, false); return Task.FromResult(session); } return EmptyResult; }
public Task<CompletableSynchronizedStorageSession> TryAdapt(OutboxTransaction transaction, ContextBag context) { var outboxTransaction = transaction as SqlOutboxTransaction; if (outboxTransaction != null) { CompletableSynchronizedStorageSession session = new StorageSession(outboxTransaction.Connection, outboxTransaction.Transaction, false); return Task.FromResult(session); } return EmptyResult; }
public Task<OutboxTransaction> BeginTransaction(ContextBag context) { var session = documentStore.OpenAsyncSession(); session.Advanced.UseOptimisticConcurrency = true; context.Set(session); var transaction = new RavenDBOutboxTransaction(session); return Task.FromResult<OutboxTransaction>(transaction); }
public async Task<IEnumerable<UnicastRoutingStrategy>> Route(Type messageType, IDistributionPolicy distributionPolicy, ContextBag contextBag) { var typesToRoute = messageMetadataRegistry.GetMessageMetadata(messageType).MessageHierarchy; var subscribers = await GetSubscribers(contextBag, typesToRoute).ConfigureAwait(false); var selectedDestinations = SelectDestinationsForEachEndpoint(distributionPolicy, subscribers); return selectedDestinations.Select(destination => new UnicastRoutingStrategy(destination)); }
public Task Unsubscribe(Subscriber subscriber, MessageType messageType, ContextBag context) { ConcurrentDictionary<string, Subscriber> dict; if (storage.TryGetValue(messageType, out dict)) { Subscriber _; dict.TryRemove(subscriber.TransportAddress, out _); } return TaskEx.CompletedTask; }
public Task<OutboxMessage> Get(string messageId, ContextBag context) { StoredMessage storedMessage; if (!storage.TryGetValue(messageId, out storedMessage)) { return NoOutboxMessageTask; } return Task.FromResult(new OutboxMessage(messageId, storedMessage.TransportOperations)); }
public void ShouldAllowMonkeyPatching() { var contextBag = new ContextBag(); contextBag.Set("MonkeyPatch", "some string"); string theValue; ((ReadOnlyContextBag) contextBag).TryGet("MonkeyPatch", out theValue); Assert.AreEqual("some string", theValue); }
internal override async Task <CompletableSynchronizedStorageSession> TryAdaptTransportConnection(TransportTransaction transportTransaction, ContextBag context, IConnectionManager connectionBuilder, Func <DbConnection, DbTransaction, bool, StorageSession> storageSessionFactory) { // Transport supports DTC and uses TxScope owned by the transport var scopeTx = Transaction.Current; if (transportTransaction.TryGet(out Transaction transportTx) && scopeTx != null && transportTx != scopeTx) { throw new Exception("A TransactionScope has been opened in the current context overriding the one created by the transport. " + "This setup can result in inconsistent data because operations done via connections enlisted in the context scope won't be committed " + "atomically with the receive transaction. To manually control the TransactionScope in the pipeline switch the transport transaction mode " + $"to values lower than '{nameof(TransportTransactionMode.TransactionScope)}'."); } var ambientTransaction = transportTx ?? scopeTx; if (ambientTransaction == null) { //Other modes handled by creating a new session. return(null); } var connection = await connectionBuilder.OpenConnection(context.GetIncomingMessage()).ConfigureAwait(false); connection.EnlistTransaction(ambientTransaction); return(storageSessionFactory(connection, null, true)); }
public Task <TSagaData> Get <TSagaData>(string propertyName, object propertyValue, SynchronizedStorageSession session, ContextBag context) where TSagaData : class, IContainSagaData { var key = new CorrelationId(typeof(TSagaData), propertyName, propertyValue); if (byCorrelationId.TryGetValue(key, out var id)) { // this isn't updated atomically and may return null for an entry that has been indexed but not inserted yet return(Get <TSagaData>(id, session, context)); } return(CachedSagaDataTask <TSagaData> .Default); }
public Task Complete(IContainSagaData sagaData, SynchronizedStorageSession session, ContextBag context) { ((InMemorySynchronizedStorageSession)session).Enlist(() => { var entry = GetEntry(context, sagaData.Id); if (sagasCollection.Remove(new KeyValuePair <Guid, Entry>(sagaData.Id, entry)) == false) { throw new Exception("Saga can't be completed as it was updated by another process."); } // saga removed // clean the index if (Equals(entry.CorrelationId, NoCorrelationId) == false) { byCorrelationIdCollection.Remove(new KeyValuePair <CorrelationId, Guid>(entry.CorrelationId, sagaData.Id)); } }); return(TaskEx.CompletedTask); }
public Task <OutboxTransaction> BeginTransaction(ContextBag context) { return(Task.FromResult <OutboxTransaction>(new NoOpOutboxTransaction())); }
public Task <CompletableSynchronizedStorageSession> TryAdapt(TransportTransaction transportTransaction, ContextBag context) { return(EmptyResult); }
public Task Update(IContainSagaData sagaData, SynchronizedStorageSession session, ContextBag context) { // store the schema version in case it has changed var container = context.Get <SagaDataContainer>($"{SagaContainerContextKeyPrefix}{sagaData.Id}"); var documentSession = session.RavenSession(); documentSession.StoreSchemaVersionInMetadata(container); // dirty tracking will do the rest for us return(Task.CompletedTask); }
public async Task Save(IContainSagaData sagaData, SagaCorrelationProperty correlationProperty, SynchronizedStorageSession session, ContextBag context) { var documentSession = session.RavenSession(); if (sagaData == null) { return; } if (correlationProperty == null) { return; } var container = new SagaDataContainer { Id = DocumentIdForSagaData(documentSession, sagaData), Data = sagaData, IdentityDocId = SagaUniqueIdentity.FormatId(sagaData.GetType(), correlationProperty.Name, correlationProperty.Value), }; await documentSession.StoreAsync(container, string.Empty, container.Id).ConfigureAwait(false); documentSession.StoreSchemaVersionInMetadata(container); var sagaUniqueIdentity = new SagaUniqueIdentity { Id = container.IdentityDocId, SagaId = sagaData.Id, UniqueValue = correlationProperty.Value, SagaDocId = container.Id }; await documentSession.StoreAsync(sagaUniqueIdentity, changeVector : string.Empty, id : container.IdentityDocId).ConfigureAwait(false); documentSession.StoreSchemaVersionInMetadata(sagaUniqueIdentity); }
public Task <ICompletableSynchronizedStorageSession> TryAdapt(IOutboxTransaction transaction, ContextBag context, CancellationToken cancellationToken = default) { if (transaction is NonDurableOutboxTransaction inMemOutboxTransaction) { ICompletableSynchronizedStorageSession session = new NonDurableSynchronizedStorageSession(inMemOutboxTransaction.Transaction); return(Task.FromResult(session)); } return(EmptyTask); }
public Task <IEnumerable <Subscriber> > GetSubscriberAddressesForMessage(IEnumerable <MessageType> messageTypes, ContextBag context) { var result = new HashSet <Subscriber>(); foreach (var m in messageTypes) { if (storage.TryGetValue(m, out var list)) { result.UnionWith(list.Values); } } return(Task.FromResult((IEnumerable <Subscriber>)result)); }
public Task Dispatch(TransportOperations outgoingMessages, TransportTransaction transaction, ContextBag context) { return(DispatcherAction(outgoingMessages)); }
public async Task <T> Get <T>(Guid sagaId, SynchronizedStorageSession session, ContextBag context) where T : class, IContainSagaData { var documentSession = session.RavenSession(); var docId = DocumentIdForSagaData(documentSession, typeof(T), sagaId); var container = await documentSession.LoadAsync <SagaDataContainer>(docId).ConfigureAwait(false); if (container == null) { return(default);
async Task <IEnumerable <Subscriber> > GetAddressesForEndpoint(string endpoint, MessageType messageType, ContextBag emptyContext) { var messageTypes = new List <MessageType> { messageType }; var addressesForMessage = await subscriptionStorage.GetSubscriberAddressesForMessage(messageTypes, emptyContext) .ConfigureAwait(false); return(addressesForMessage .Where(subscriber => { return string.Equals(subscriber.Endpoint, endpoint, StringComparison.OrdinalIgnoreCase); })); }
public Task SetAsDispatched(string messageId, ContextBag options) { return(TaskEx.CompletedTask); }
Task UnsubscribeFromEndpoint(IEnumerable <Subscriber> addressesForEndpoint, MessageType messageType, ContextBag emptyContext) { var tasks = addressesForEndpoint .Select(address => subscriptionStorage.Unsubscribe( subscriber: address, messageType: messageType, context: emptyContext )); return(Task.WhenAll(tasks)); }
public Task <OutboxMessage> Get(string messageId, ContextBag options) { return(NoOutboxMessageTask); }
public Task <ICompletableSynchronizedStorageSession> OpenSession(ContextBag contextBag, CancellationToken cancellationToken = default) => Task.FromResult <ICompletableSynchronizedStorageSession>(new NonDurableSynchronizedStorageSession());
public Task <TSagaData> Get <TSagaData>(Guid sagaId, SynchronizedStorageSession session, ContextBag context) where TSagaData : class, IContainSagaData { if (sagas.TryGetValue(sagaId, out var value)) { SetEntry(context, sagaId, value); var data = value.GetSagaCopy(); return(Task.FromResult((TSagaData)data)); } return(CachedSagaDataTask <TSagaData> .Default); }
public CosmosOutboxTransaction(ContainerHolderResolver resolver, ContextBag context) { StorageSession = new StorageSession(resolver, context, false); }
public async Task SendLocal(IFullMessage message, IDictionary <string, string> headers = null) { Logger.Write(LogLevel.Debug, () => $"Sending local message of type [{message.Message.GetType().FullName}]"); while (!Bus.BusOnline) { await Task.Delay(100).ConfigureAwait(false); } headers = headers ?? new Dictionary <string, string>(); var contextBag = new ContextBag(); // Hack to get all the events to invoker without NSB deserializing contextBag.Set(Defaults.LocalHeader, message.Message); var processed = false; var numberOfDeliveryAttempts = 0; var messageId = Guid.NewGuid().ToString(); var corrId = ""; if (message?.Headers?.ContainsKey(Headers.CorrelationId) ?? false) { corrId = message.Headers[Headers.CorrelationId]; } while (!processed) { var transportTransaction = new TransportTransaction(); var tokenSource = new CancellationTokenSource(); var messageType = message.Message.GetType(); if (!messageType.IsInterface) { messageType = _mapper.GetMappedTypeFor(messageType) ?? messageType; } var finalHeaders = message.Headers.Merge(headers); finalHeaders[Headers.EnclosedMessageTypes] = messageType.AssemblyQualifiedName; finalHeaders[Headers.MessageIntent] = MessageIntentEnum.Send.ToString(); finalHeaders[Headers.MessageId] = messageId; finalHeaders[Headers.CorrelationId] = corrId; try { // Don't re-use the event id for the message id var messageContext = new MessageContext(messageId, finalHeaders, Marker, transportTransaction, tokenSource, contextBag); await Bus.OnMessage(messageContext).ConfigureAwait(false); _metrics.Mark("Dispatched Messages", Unit.Message); processed = true; } catch (ObjectDisposedException) { // NSB transport has been disconnected throw new OperationCanceledException(); } catch (Exception ex) { _metrics.Mark("Dispatched Errors", Unit.Errors); ++numberOfDeliveryAttempts; // Don't retry a cancelation if (tokenSource.IsCancellationRequested) { numberOfDeliveryAttempts = Int32.MaxValue; } var messageBytes = _serializer.Serialize(message.Message); var errorContext = new ErrorContext(ex, finalHeaders, messageId, messageBytes, transportTransaction, numberOfDeliveryAttempts); if (await Bus.OnError(errorContext).ConfigureAwait(false) == ErrorHandleResult.Handled || tokenSource.IsCancellationRequested) { break; } } } }
public abstract Task <IContainSagaData> Find(IBuilder builder, SagaFinderDefinition finderDefinition, SynchronizedStorageSession storageSession, ContextBag context, object message);
public async Task SendLocal(IFullMessage[] messages, IDictionary <string, string> headers = null) { Logger.Write(LogLevel.Debug, () => $"Sending {messages.Length} bulk local messages"); while (!Bus.BusOnline) { await Task.Delay(100).ConfigureAwait(false); } headers = headers ?? new Dictionary <string, string>(); await messages.GroupBy(x => x.Message.GetType()).ToArray().StartEachAsync(3, async(group) => { var groupedMessages = group.Select(x => x.Message as IDelayedMessage).ToArray(); var contextBag = new ContextBag(); // Hack to get all the events to invoker without NSB deserializing contextBag.Set(Defaults.LocalBulkHeader, groupedMessages); var processed = false; var numberOfDeliveryAttempts = 0; var messageId = Guid.NewGuid().ToString(); while (!processed) { var transportTransaction = new TransportTransaction(); var tokenSource = new CancellationTokenSource(); var messageType = group.Key; if (!messageType.IsInterface) { messageType = _mapper.GetMappedTypeFor(messageType) ?? messageType; } var finalHeaders = headers.Merge(new Dictionary <string, string>() { [Headers.EnclosedMessageTypes] = messageType.AssemblyQualifiedName, [Headers.MessageIntent] = MessageIntentEnum.Send.ToString(), [Headers.MessageId] = messageId }); try { // Don't re-use the event id for the message id var messageContext = new MessageContext(messageId, finalHeaders, Marker, transportTransaction, tokenSource, contextBag); await Bus.OnMessage(messageContext).ConfigureAwait(false); _metrics.Mark("Dispatched Messages", Unit.Message, groupedMessages.Length); processed = true; } catch (ObjectDisposedException) { // NSB transport has been disconnected throw new OperationCanceledException(); } catch (Exception ex) { _metrics.Mark("Dispatched Errors", Unit.Errors, groupedMessages.Length); ++numberOfDeliveryAttempts; // Don't retry a cancelation if (tokenSource.IsCancellationRequested) { numberOfDeliveryAttempts = Int32.MaxValue; } var messageList = groupedMessages.ToList(); foreach (var message in groupedMessages) { var messageBytes = _serializer.Serialize(message.Message); var errorContext = new ErrorContext(ex, message.Headers.Merge(finalHeaders), messageId, messageBytes, transportTransaction, numberOfDeliveryAttempts); if (await Bus.OnError(errorContext).ConfigureAwait(false) == ErrorHandleResult.Handled) { messageList.Remove(message); } } if (messageList.Count == 0) { break; } groupedMessages = messageList.ToArray(); } } }).ConfigureAwait(false); }
public async Task <IContainSagaData> Load(ISagaPersister persister, string sagaId, SynchronizedStorageSession storageSession, ContextBag context) { return(await persister.Get <T>(Guid.Parse(sagaId), storageSession, context).ConfigureAwait(false)); }
public Task Dispatch(TransportOperations outgoingMessages, TransportTransaction transaction, ContextBag context) { foreach (var operation in outgoingMessages.UnicastTransportOperations) { var destinationBasePath = DirectoryBuilder.BuildBasePath(operation.Destination); var nativeMessageId = Guid.NewGuid().ToString(); var bodyPath = Path.Combine(destinationBasePath, ".bodies", $"{nativeMessageId}.xml"); var bodyDirectory = Path.GetDirectoryName(bodyPath); if (bodyDirectory != null) { if (!Directory.Exists(bodyDirectory)) { Directory.CreateDirectory(bodyDirectory); } } File.WriteAllBytes(bodyPath, operation.Message.Body); var messageContents = new List <string> { bodyPath, HeaderSerializer.Serialize(operation.Message.Headers) }; var messagePath = Path.Combine(destinationBasePath, $"{nativeMessageId}.txt"); // Write to a temp file first so an atomic move can be done. // This avoids the file being locked when the receiver triest to process it. var tempFilePath = Path.GetTempFileName(); File.WriteAllLines(tempFilePath, messageContents); File.Move(tempFilePath, messagePath); } return(Task.CompletedTask); }
public Task <bool> TryRemove(string timeoutId, ContextBag context) { throw new Exception("Simulated exception on removing timeout data."); }
public Task <IEnumerable <Subscriber> > GetSubscriberAddressesForMessage(IEnumerable <MessageType> messageHierarchy, ContextBag context) { var types = messageHierarchy.ToList(); if (cacheFor == null) { return(GetSubscriptions(types)); } var key = GetKey(types); var cacheItem = Cache.GetOrAdd(key, valueFactory: _ => new CacheItem { Stored = DateTime.UtcNow, Subscribers = GetSubscriptions(types) }); var age = DateTime.UtcNow - cacheItem.Stored; if (age >= cacheFor) { cacheItem.Subscribers = GetSubscriptions(types); cacheItem.Stored = DateTime.UtcNow; } return(cacheItem.Subscribers); }
public Task RemoveTimeoutBy(Guid sagaId, ContextBag context) { throw new NotImplementedException(); }
public async Task <TSagaData> Get <TSagaData>(Guid sagaId, SynchronizedStorageSession session, ContextBag context, CancellationToken cancellationToken = default) where TSagaData : class, IContainSagaData { var result = await Get <TSagaData>(sagaId, session, cancellationToken).ConfigureAwait(false); return(SetConcurrency(result, context)); }
public Task Store(OutboxMessage message, OutboxTransaction transaction, ContextBag options) { return(TaskEx.CompletedTask); }
public Task <ICompletableSynchronizedStorageSession> TryAdapt(TransportTransaction transportTransaction, ContextBag context, CancellationToken cancellationToken = default) { if (transportTransaction.TryGet(out Transaction ambientTransaction)) { var transaction = new NonDurableTransaction(); ICompletableSynchronizedStorageSession session = new NonDurableSynchronizedStorageSession(transaction); ambientTransaction.EnlistVolatile(new EnlistmentNotification2(transaction), EnlistmentOptions.None); return(Task.FromResult(session)); } return(EmptyTask); }
public override async Task <IContainSagaData> Find(IServiceProvider builder, SagaFinderDefinition finderDefinition, SynchronizedStorageSession storageSession, ContextBag context, object message, IReadOnlyDictionary <string, string> messageHeaders) { var customFinderType = (Type)finderDefinition.Properties["custom-finder-clr-type"]; var finder = (IFindSagas <TSagaData> .Using <TMessage>)builder.GetService(customFinderType); return(await finder .FindBy((TMessage)message, storageSession, context) .ThrowIfNull() .ConfigureAwait(false)); }