public async Task <T> Get <T>(string propertyName, object propertyValue, SynchronizedStorageSession session, ContextBag context)
            where T : class, IContainSagaData
        {
            var documentSession = session.RavenSession();

            var lookupId = SagaUniqueIdentity.FormatId(typeof(T), propertyName, propertyValue);

            //store it in the context to be able to optimize deletes for legacy sagas that don't have the id in metadata
            context.Set(UniqueDocIdKey, lookupId);

            var lookup = await documentSession
                         .Include("SagaDocId") //tell raven to pull the saga doc as well to save us a round-trip
                         .LoadAsync <SagaUniqueIdentity>(lookupId)
                         .ConfigureAwait(false);

            if (lookup != null)
            {
                documentSession.Advanced.Evict(lookup);

                return(lookup.SagaDocId != null
                    ? await documentSession.LoadAsync <T>(lookup.SagaDocId).ConfigureAwait(false) //if we have a saga id we can just load it
                    : await Get <T>(lookup.SagaId, session, context).ConfigureAwait(false));      //if not this is a saga that was created pre 3.0.4 so we fallback to a get instead
            }

            return(default(T));
        }
예제 #2
0
        public async Task <T> Get <T>(string propertyName, object propertyValue, SynchronizedStorageSession session, ContextBag context)
            where T : class, IContainSagaData
        {
            var documentSession = session.RavenSession();

            var lookupId = SagaUniqueIdentity.FormatId(typeof(T), propertyName, propertyValue);

            var lookup = await documentSession
                         .Include("SagaDocId") //tell raven to pull the saga doc as well to save us a round-trip
                         .LoadAsync <SagaUniqueIdentity>(lookupId)
                         .ConfigureAwait(false);

            if (lookup != null)
            {
                documentSession.Advanced.Evict(lookup);

                // If we have a saga id we can just load it, should have been included in the round-trip already
                var container = await documentSession.LoadAsync <SagaDataContainer>(lookup.SagaDocId).ConfigureAwait(false);

                if (container != null)
                {
                    if (container.IdentityDocId == null)
                    {
                        container.IdentityDocId = lookupId;
                    }
                    context.Set($"{SagaContainerContextKeyPrefix}{container.Data.Id}", container);
                    return((T)container.Data);
                }
            }

            return(default(T));
        }
        public Task <T> Get <T>(Guid sagaId, SynchronizedStorageSession session, ContextBag context)
            where T : class, IContainSagaData
        {
            var documentSession = session.RavenSession();

            return(documentSession.LoadAsync <T>(sagaId));
        }
예제 #4
0
        public async Task Save(IContainSagaData sagaData, SagaCorrelationProperty correlationProperty, SynchronizedStorageSession session, ContextBag context)
        {
            var documentSession = session.RavenSession();

            if (sagaData == null)
            {
                return;
            }

            var container = new SagaDataContainer
            {
                Id   = DocumentIdForSagaData(documentSession, sagaData),
                Data = sagaData
            };

            if (correlationProperty == null)
            {
                return;
            }

            container.IdentityDocId = SagaUniqueIdentity.FormatId(sagaData.GetType(), correlationProperty.Name, correlationProperty.Value);

            await documentSession.StoreAsync(container, string.Empty, container.Id).ConfigureAwait(false);

            await documentSession.StoreAsync(new SagaUniqueIdentity
            {
                Id          = container.IdentityDocId,
                SagaId      = sagaData.Id,
                UniqueValue = correlationProperty.Value,
                SagaDocId   = container.Id
            }, changeVector : string.Empty, id : container.IdentityDocId).ConfigureAwait(false);
        }
예제 #5
0
    public Task <OrderSagaData> FindBy(StartOrder message, SynchronizedStorageSession storageSession, ReadOnlyContextBag context)
    {
        var session = storageSession.RavenSession();

        // if the instance is null a new saga will be automatically created if
        // the Saga handles the message as IAmStartedByMessages<StartOrder>; otherwise an exception is raised.
        return(session.LoadByUniqueConstraintAsync <OrderSagaData>(d => d.OrderId, message.OrderId));
    }
예제 #6
0
                public Task <SagaFinderSagaData> FindBy(StartSagaMessage message, SynchronizedStorageSession session, ReadOnlyContextBag options, CancellationToken cancellationToken = default)
                {
                    if (Context.SagaId == Guid.Empty)
                    {
                        return(Task.FromResult(default(SagaFinderSagaData)));
                    }

                    return(session.RavenSession().LoadAsync <SagaFinderSagaData>(Context.SagaId.ToString(), cancellationToken));
                }
예제 #7
0
        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);
예제 #8
0
        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);
        }
예제 #9
0
            public Task <MySagaData> FindBy(MyMessage message, SynchronizedStorageSession storageSession, ReadOnlyContextBag context)
            {
                // the custom finding logic here, e.g.
                IAsyncDocumentSession ravenSession = storageSession.RavenSession();
                MySagaData            sagaData     = ravenSession
                                                     .Query <MySagaData>()
                                                     .SingleOrDefault(x =>
                                                                      x.SomeID == message.SomeID &&
                                                                      x.SomeData == message.SomeData);

                return(Task.FromResult(sagaData));
            }
예제 #10
0
        public Task Complete(IContainSagaData sagaData, SynchronizedStorageSession session, ContextBag context)
        {
            var documentSession = session.RavenSession();
            var container       = context.Get <SagaDataContainer>($"{SagaContainerContextKeyPrefix}{sagaData.Id}");

            documentSession.Delete(container);
            if (container.IdentityDocId != null)
            {
                documentSession.Advanced.Defer(new DeleteCommandData(container.IdentityDocId, null));
            }
            return(Task.CompletedTask);
        }
        public async Task Save(IContainSagaData sagaData, SagaCorrelationProperty correlationProperty, SynchronizedStorageSession session, ContextBag context)
        {
            var documentSession = session.RavenSession();

            if (sagaData == null)
            {
                return;
            }

            await documentSession.StoreAsync(sagaData).ConfigureAwait(false);

            if (correlationProperty == null)
            {
                return;
            }

            await CreateSagaUniqueIdentity(sagaData, correlationProperty, documentSession).ConfigureAwait(false);
        }
예제 #12
0
        public async Task <T> Get <T>(Guid sagaId, SynchronizedStorageSession session, ContextBag context, CancellationToken cancellationToken = default)
            where T : class, IContainSagaData
        {
            var documentSession = session.RavenSession();
            var docId           = DocumentIdForSagaData(documentSession, typeof(T), sagaId);

            if (enablePessimisticLocking)
            {
                var index = await AcquireLease(documentSession.Advanced.DocumentStore, docId, cancellationToken).ConfigureAwait(false);

                // only true if we always have synchronized storage session around which is a valid assumption
                context.Get <SagaDataLeaseHolder>().DocumentsIdsAndIndexes.Add((docId, index));
            }

            var container = await documentSession.LoadAsync <SagaDataContainer>(docId, cancellationToken).ConfigureAwait(false);

            if (container == null)
            {
                return(default);
        public async Task Complete(IContainSagaData sagaData, SynchronizedStorageSession session, ContextBag context)
        {
            var documentSession = session.RavenSession();

            documentSession.Delete(sagaData);

            string      uniqueDocumentId;
            RavenJToken uniqueDocumentIdMetadata;
            var         metadata = await documentSession.Advanced.GetMetadataForAsync(sagaData).ConfigureAwait(false);

            if (metadata.TryGetValue(UniqueDocIdKey, out uniqueDocumentIdMetadata))
            {
                uniqueDocumentId = uniqueDocumentIdMetadata.Value <string>();
            }
            else
            {
                context.TryGet(UniqueDocIdKey, out uniqueDocumentId);
            }

            if (string.IsNullOrEmpty(uniqueDocumentId))
            {
                var uniqueDoc = await documentSession.Query <SagaUniqueIdentity>()
                                .SingleOrDefaultAsync(d => d.SagaId == sagaData.Id)
                                .ConfigureAwait(false);

                if (uniqueDoc != null)
                {
                    documentSession.Delete(uniqueDoc);
                }
            }
            else
            {
                documentSession.Advanced.Defer(new DeleteCommandData
                {
                    Key = uniqueDocumentId
                });
            }
        }
예제 #14
0
        public async Task Save(IContainSagaData sagaData, SagaCorrelationProperty correlationProperty, SynchronizedStorageSession session, ContextBag context, CancellationToken cancellationToken = default)
        {
            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, cancellationToken).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, token : cancellationToken).ConfigureAwait(false);

            documentSession.StoreSchemaVersionInMetadata(sagaUniqueIdentity);
        }
예제 #15
0
    public Task <OrderSagaData> FindBy(PaymentTransactionCompleted message, SynchronizedStorageSession storageSession, ReadOnlyContextBag context)
    {
        var session = storageSession.RavenSession();

        return(session.LoadByUniqueConstraintAsync <OrderSagaData>(d => d.PaymentTransactionId, message.PaymentTransactionId));
    }
    public Task <OrderSagaData> FindBy(CompleteOrder message, SynchronizedStorageSession storageSession, ReadOnlyContextBag context)
    {
        IAsyncDocumentSession session = storageSession.RavenSession();

        return(session.LoadByUniqueConstraintAsync <OrderSagaData>(d => d.OrderId, message.OrderId));
    }