static IServiceFabricStorageSession GetServiceFabricSession(this ISynchronizedStorageSession session) { if (session is IServiceFabricStorageSession storageSession) { return(storageSession); } throw new Exception("The endpoint has not been configured to use Service Fabric persistence."); }
public Task Update(IContainSagaData sagaData, ISynchronizedStorageSession session, ContextBag context, CancellationToken cancellationToken = default) { var storageSession = (StorageSession)session; var partitionKey = GetPartitionKey(context, sagaData.Id); storageSession.AddOperation(new SagaUpdate(sagaData, partitionKey, serializer, context)); return(Task.CompletedTask); }
/// <summary> /// Retrieves the current MongoDB client session from the context. /// </summary> public static IClientSessionHandle GetClientSession(this ISynchronizedStorageSession session) { Guard.AgainstNull(nameof(session), session); if (session is IMongoSessionProvider storageSession) { return(storageSession.MongoSession); } throw new Exception($"Cannot access the synchronized storage session. Ensure that 'EndpointConfiguration.UsePersistence<{nameof(MongoPersistence)}>()' has been called."); }
/// <summary> /// Retrieves the shared <see cref="ICosmosStorageSession"/> from the <see cref="ISynchronizedStorageSession"/>. /// </summary> public static ICosmosStorageSession CosmosPersistenceSession(this ISynchronizedStorageSession session) { Guard.AgainstNull(nameof(session), session); if (session is IWorkWithSharedTransactionalBatch workWith) { return(workWith.Create()); } throw new Exception($"Cannot access the synchronized storage session. Ensure that 'EndpointConfiguration.UsePersistence<{nameof(CosmosPersistence)}>()' has been called."); }
public Task <TSagaData> Get <TSagaData>(Guid sagaId, ISynchronizedStorageSession session, ContextBag context, CancellationToken cancellationToken = default) 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 Task Update(IContainSagaData sagaData, ISynchronizedStorageSession session, ContextBag context, CancellationToken cancellationToken = default) { ((NonDurableSynchronizedStorageSession)session).Enlist(() => { var entry = GetEntry(context, sagaData.Id); if (sagas.TryUpdate(sagaData.Id, entry.UpdateTo(sagaData), entry) == false) { throw new Exception($"NonDurableSagaPersister concurrency violation: saga entity Id[{sagaData.Id}] already saved."); } }); return(Task.CompletedTask); }
public async Task Complete(IContainSagaData sagaData, ISynchronizedStorageSession session, ContextBag context, CancellationToken cancellationToken = default) { var storageSession = (StorageSession)session; var sagaDataType = sagaData.GetType(); var version = storageSession.RetrieveVersion(sagaDataType); var result = await storageSession.DeleteOneAsync(sagaDataType, filterBuilder.Eq(idElementName, sagaData.Id)& filterBuilder.Eq(versionElementName, version), cancellationToken).ConfigureAwait(false); if (result.DeletedCount != 1) { throw new Exception("Saga can't be completed because it was updated by another process."); } }
public async Task Update(IContainSagaData sagaData, ISynchronizedStorageSession session, ContextBag context, CancellationToken cancellationToken = default) { var storageSession = (StorageSession)session; var sagaDataType = sagaData.GetType(); var version = storageSession.RetrieveVersion(sagaDataType); var document = sagaData.ToBsonDocument().SetElement(new BsonElement(versionElementName, version + 1)); var result = await storageSession.ReplaceOneAsync(sagaDataType, filterBuilder.Eq(idElementName, sagaData.Id)& filterBuilder.Eq(versionElementName, version), document, cancellationToken).ConfigureAwait(false); if (result.ModifiedCount != 1) { throw new Exception($"The '{sagaDataType.Name}' saga with id '{sagaData.Id}' was updated by another process or no longer exists."); } }
public async Task Complete(IContainSagaData sagaData, ISynchronizedStorageSession session, ContextBag context, CancellationToken cancellationToken = default) { var storageSession = (StorageSession)session; var entry = GetEntry(context, sagaData.Id); var sagaInfo = sagaInfoCache.GetInfo(sagaData.GetType()); var sagas = await storageSession.Sagas(sagaInfo.SagaAttribute.CollectionName, cancellationToken : cancellationToken).ConfigureAwait(false); var conditionalValue = await sagas.TryRemoveAsync(storageSession.Transaction, sagaData.Id, storageSession.TransactionTimeout, cancellationToken).ConfigureAwait(false); if (conditionalValue.HasValue && conditionalValue.Value.Data != entry.Data) { throw new Exception("Saga can't be completed as it was updated by another process."); } }
public async Task <TSagaData> Get <TSagaData>(Guid sagaId, ISynchronizedStorageSession session, ContextBag context, CancellationToken cancellationToken = default) where TSagaData : class, IContainSagaData { var storageSession = (StorageSession)session; var sagaInfo = sagaInfoCache.GetInfo(typeof(TSagaData)); var sagas = await storageSession.Sagas(sagaInfo.SagaAttribute.CollectionName, cancellationToken : cancellationToken).ConfigureAwait(false); var conditionalValue = await sagas.TryGetValueAsync(storageSession.Transaction, sagaId, LockMode.Update, storageSession.TransactionTimeout, cancellationToken).ConfigureAwait(false); if (conditionalValue.HasValue) { SetEntry(context, sagaId, conditionalValue.Value); return(sagaInfo.FromSagaEntry <TSagaData>(conditionalValue.Value)); } return(default);
public async Task <TSagaData> Get <TSagaData>(Guid sagaId, ISynchronizedStorageSession session, ContextBag context, CancellationToken cancellationToken = default) where TSagaData : class, IContainSagaData { var storageSession = (StorageSession)session; // reads need to go directly var container = storageSession.ContainerHolder.Container; var partitionKey = GetPartitionKey(context, sagaId); bool sagaNotFound; TSagaData sagaData; if (!pessimisticLockingEnabled) { (sagaNotFound, sagaData) = await ReadSagaData <TSagaData>(sagaId, context, container, partitionKey, cancellationToken).ConfigureAwait(false); // if the previous lookup by id wasn't successful and the migration mode is enabled try to query for the saga data because the saga id probably represents // the saga id of the migrated saga. if (sagaNotFound && migrationModeEnabled && await FindSagaIdInMigrationMode(sagaId, context, container, cancellationToken).ConfigureAwait(false) is { } migratedSagaId) { partitionKey = GetPartitionKey(context, migratedSagaId); (_, sagaData) = await ReadSagaData <TSagaData>(migratedSagaId, context, container, partitionKey, cancellationToken).ConfigureAwait(false); } return(sagaData); } (sagaNotFound, sagaData) = await AcquireLease <TSagaData>(sagaId, context, container, partitionKey, cancellationToken).ConfigureAwait(false); // if the previous lookup by id wasn't successful and the migration mode is enabled try to query for the saga data because the saga id probably represents // the saga id of the migrated saga. if (sagaNotFound && migrationModeEnabled && await FindSagaIdInMigrationMode(sagaId, context, container, cancellationToken).ConfigureAwait(false) is { } previousSagaId) { partitionKey = GetPartitionKey(context, previousSagaId); (_, sagaData) = await AcquireLease <TSagaData>(previousSagaId, context, container, partitionKey, cancellationToken).ConfigureAwait(false); } storageSession.AddOperation(new SagaReleaseLock(sagaData, partitionKey, serializer, context)); return(sagaData); }
public Task Complete(IContainSagaData sagaData, ISynchronizedStorageSession session, ContextBag context, CancellationToken cancellationToken = default) { ((NonDurableSynchronizedStorageSession)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(Task.CompletedTask); }
async Task <TSagaData> GetSagaData <TSagaData>(string elementName, object elementValue, ISynchronizedStorageSession session, CancellationToken cancellationToken) { var storageSession = (StorageSession)session; var document = await storageSession.Find <TSagaData>(new BsonDocument(elementName, BsonValue.Create(elementValue)), cancellationToken).ConfigureAwait(false); if (document != null) { var version = document.GetValue(versionElementName); storageSession.StoreVersion <TSagaData>(version.AsInt32); return(BsonSerializer.Deserialize <TSagaData>(document)); } return(default);
public async Task Save(IContainSagaData sagaData, SagaCorrelationProperty correlationProperty, ISynchronizedStorageSession session, ContextBag context, CancellationToken cancellationToken = default) { var storageSession = (StorageSession)session; var sagaDataType = sagaData.GetType(); var document = sagaData.ToBsonDocument(); document.Add(versionElementName, 0); await storageSession.InsertOneAsync(sagaDataType, document, cancellationToken).ConfigureAwait(false); }
public Task Save(IContainSagaData sagaData, SagaCorrelationProperty correlationProperty, ISynchronizedStorageSession session, ContextBag context, CancellationToken cancellationToken = default) { ((NonDurableSynchronizedStorageSession)session).Enlist(() => { var correlationId = NoCorrelationId; if (correlationProperty != SagaCorrelationProperty.None) { correlationId = new CorrelationId(sagaData.GetType(), correlationProperty); if (byCorrelationId.TryAdd(correlationId, sagaData.Id) == false) { throw new InvalidOperationException($"The saga with the correlation id 'Name: {correlationProperty.Name} Value: {correlationProperty.Value}' already exists"); } } var entry = new Entry(sagaData, correlationId); if (sagas.TryAdd(sagaData.Id, entry) == false) { throw new Exception("A saga with this identifier already exists. This should never happened as saga identifier are meant to be unique."); } }); return(Task.CompletedTask); }
public Task <TSagaData> Get <TSagaData>(string propertyName, object propertyValue, ISynchronizedStorageSession session, ContextBag context, CancellationToken cancellationToken = default) 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, cancellationToken)); } return(CachedSagaDataTask <TSagaData> .Default); }
public Task <TSagaData> Get <TSagaData>(Guid sagaId, ISynchronizedStorageSession session, ContextBag context, CancellationToken cancellationToken = default) where TSagaData : class, IContainSagaData => GetSagaData <TSagaData>(idElementName, sagaId, session, cancellationToken);
public async Task <TSagaData> Get <TSagaData>(string propertyName, object propertyValue, ISynchronizedStorageSession session, ContextBag context, CancellationToken cancellationToken = default) where TSagaData : class, IContainSagaData { var storageSession = (StorageSession)session; // Saga ID needs to be calculated the same way as in SagaIdGenerator does var sagaId = CosmosSagaIdGenerator.Generate(typeof(TSagaData), propertyName, propertyValue); // reads need to go directly var container = storageSession.ContainerHolder.Container; var partitionKey = GetPartitionKey(context, sagaId); TSagaData sagaData; if (!pessimisticLockingEnabled) { (_, sagaData) = await ReadSagaData <TSagaData>(sagaId, context, container, partitionKey, cancellationToken).ConfigureAwait(false); return(sagaData); } (_, sagaData) = await AcquireLease <TSagaData>(sagaId, context, container, partitionKey, cancellationToken).ConfigureAwait(false); storageSession.AddOperation(new SagaReleaseLock(sagaData, partitionKey, serializer, context)); return(sagaData); }
/// <summary> /// Gets the current context ServiceFabricPersistence <see cref="IServiceFabricStorageSession"/>. /// </summary> public static IServiceFabricStorageSession ServiceFabricSession(this ISynchronizedStorageSession session) { Guard.AgainstNull(nameof(session), session); return(GetServiceFabricSession(session)); }
public Task <TSagaData> Get <TSagaData>(string propertyName, object propertyValue, ISynchronizedStorageSession session, ContextBag context, CancellationToken cancellationToken = default) where TSagaData : class, IContainSagaData => GetSagaData <TSagaData>(typeof(TSagaData).GetElementName(propertyName), propertyValue, session, cancellationToken);