I have a saga which represents a long-running work assignment process of a "Person" to a "Case". Several events may kick it off, and at the end of the process we have an assignment confirmation, at which point the saga completes and the Person is assigned to the Case. I would like to have a timeout for this saga so that we don't wait indefinitely for confirmation - definitely a valid business use case. No difficulties there - fairly vanilla.
The twist is that this assignment process can be blocked if someone puts the Case on hold. I have an event I can subscribe to so my assignment saga knows the Case is on hold, but unless I adjust the timeout or suspend it in some way, the assignment saga will likely time out before the Case hold is released. It doesn't make business sense to do this, so I basically want to stop the timeout clock until some other event comes in.
This same issue was mentioned here a couple years ago. Is this still not possible or are there new features in v3.x that would allow it? If not, is it a planned feature?
Thanks!
Why not remove the timeout altogether for the instance when your case is put on hold? Your saga maintains the state of the case and the calculated time when the case would have been due. This could have been set when you created the first timeout. When the case is reactivated, simply calculate the difference in time from the reactivation and the saved "deadline", and create a new timeout for that instance with the difference. You may also want to take into account the time the case was on hold and set a new deadline which you would save back to the instance state.
I don't think there is a way to tab directly to the timer and put the timeout message "on-hold"
I would have that logic inside the timeout handler on the saga. Check if the case is on hold and request another timeout without ending the saga.
Related
I am creating an ASP NET Core app, and I have certain entities, for example, a dispute for an order. After the dispute has been opened, the Creation Date property is set for it. I want to make sure that if the buyer does not answer in his dispute within 7 days, the dispute is closed automatically.
I understand that it can be done through CronJob with a certain interval, but I would like to avoid an excessive number of calls to check the date in all disputes.
Is there a proper way to schedule task calls at a specific time? I need it workable even after app restarting.
Is there a proper way to schedule task calls at a specific time?
To execute a background task/job at a user specified time, you can try to use some message queue services, such Azure Queue Storage queues that enable us to specify how long the message should be invisible to Dequeue and Peek operations by setting visibilityTimeout.
And you can implement a queue triggered background task to retrieve message(s) from the queue and close the dispute in code logic.
I have a program where I start several process instances using a cron. For each process instance I have a maximum time, and if the execution time exceeds it, I have to consider it as failure and use some specific methods.
For now what I did was simply to check, once my process instance has finished, if the elapsed time exceeds or not the given maximum time.
But what if my process instance gets blocked for some reason (e.g. server not responding)? I need to catch this event and perform failure operations as soon as the process gets blocked and timeout is exceeded.
How can I catch these two conditions?
I had a look at the FlowableEngineEventType, but there isn’t a PROCESS_BLOCKED/SUSPENDED type of event. But, even if it were, how do I fire it only if a certain amount of time has passed?
I assume that this is the same question as this from the Flowable Forum.
If you are using the Flowable HTTP Task then have a look at the documentation to see how you can set the timeouts on it and how you can react on errors there. If you are firing GET requests from your own code you would need to write your own business logic that would throw some kind of BpmnError and you would then handle that in your process.
The Flowable Process instance does not have the concept of being blocked, and you have to manually to that in your modelling.
I have a task that can be started by the user, that could take hours to run, and where there's a reasonable chance that the user will start the task multiple times during a run.
I've broken the processing of the task up into smaller batches, but the way the data looks it's very difficult to tell what's still to be processed. I batch it using messages that each process a bite sized chunk of the data.
I have thought of using a Saga to control access to starting this process, with a Saga property called Processing that I set at the start of the handler and then unset at the end of the handler. The handler does some work and sends the messages to process the data. I check the value at the start of the handler, and if it's set, then just return.
I'm using Azure storage for Saga storage, if it makes a difference for the next bit. I'm also using NSB 6
I have a few questions though:
Is this the correct approach to re-entrancy with NSB?
When is a change to Saga data persisted? (and is it different depending on the transport?)
Following on from the above, if I set a Saga value in a handler, wait a while and then reset it to its original value will it change the persistent storage at all?
Seem to be cross posted in the Particular Software google group:
https://groups.google.com/forum/#!topic/particularsoftware/p-qD5merxZQ
Sagas are very often used for such patterns. The saga instance would track progress and guard that the (sub)tasks aren't invoked multiple times but could also take actions if the expected task(s) didn't complete or is/are over time.
The saga instance data is stored after processing the message and not when updating any of the saga data properties. The logic you described would not work.
The correct way would be having a saga that orchestrates your process and having regular handlers that do the actual work.
In the saga handle method that creates the saga check if the saga was already created or already the 'busy' status and if it does not have this status send a message to do some work. This will guard that the task is only initiated once and after that the saga is stored.
The handler can now do the actual task, when it completes it can do a 'Reply' back to the saga
When the saga receives the reply it can now start any other follow up task or raise an event and it can also 'complete'.
Optimistic concurrency control and batched sends
If two message are received that create/update the same saga instance only the first writer wins. The other will fail because of optimistic concurrency control.
However, if these messages are not processed in parallel but sequential both fail unless the saga checks if the saga instance is already initialized.
The following sample demonstrates this: https://github.com/ramonsmits/docs.particular.net/tree/azure-storage-saga-optimistic-concurrency-control/samples/azure/storage-persistence/ASP_1
The client sends two identical message bodies. The saga is launched and only 1 message succeeds due to optimistic concurrency control.
Due to retries eventually the second copy will be processed to but the saga checks the saga data for a field that it knows would normally be initialized by by a message that 'starts' the saga. If that field is already initialized it assumes the message is already processed and just returns:
It also demonstrates batches sends. Messages are not immediately send until the all handlers/sagas are completed.
Saga design
The following video might help you with designing your sagas and understand the various patterns:
Integration Patterns with NServiceBus: https://www.youtube.com/watch?v=BK8JPp8prXc
Keep in mind that Azure Storage isn't transactional and does not provide locking, it is only atomic. Any work you do within a handler or saga can potentially be invoked more than once and if you use non-transactional resources then make sure that logic is idempotent.
So after a lot of testing
I don't believe that this is the right approach.
As Archer says, you can manipulate the saga data properties as much as you like, they are only saved at the end of the handler.
So if the saga receives two simultaneous messages the check for Processing will pass both times and I'll have two processes running (and in my case processing the same data twice).
The saga within a saga faces a similar problem too.
What I believe will work (and has done during my PoC testing) is using a database unique index to help out. I'm using entity framework and azure sql, so database access is not contained within the handler's transaction (this is the important difference between the database and the saga data). The database will also operate across all instances of the endpoint and generally seems like a good solution.
The table that I'm using has each of the columns that make up the saga 'id', and there is a unique index on them.
At the beginning of the handler I retrieve a row from the database. If there is a row, the handler returns (in my case this is okay, in others you could throw an exception to get the handler to run again). The first thing that the handler does (before any work, although I'm not 100% sure that it matters) is to write a row to the table. If the write fails (probably because of the unique constraint being violated) the exception puts the message back on the queue. It doesn't really matter why the database write fails, as NSB will handle it.
Then the handler does the work.
Then remove the row.
Of course there is a chance that something happens during processing of the work, so I'm also using a timestamp and another process to reset it if it's busy for too long. (still need to define 'too long' though :) )
Maybe this can help someone with a similar problem.
I'm fairly new to Gigaspaces. I am using a polling container to fetch events from a space and then dispatch these over a HTTPS connection. If the server endpoint for the connection becomes unavailable, I need to update the state of the event objects to 'blocked' and re-queue them in the space for later retries (for which I have a separate polling container that specifically looks for the blocked events).
What I'm struggling with is finding a good way to ensure the blocked event polling container does not over-rotate on the blocked events (that is, read the events, discover that the endpoint is still blocked, write them back to the space and then immediately re-read them).
Is there a way I could build in a delay in re-reading the events from the space. Options might include:
Setting/updating a timestamp on the object before writing it back, and then comparing this with the current time within the polling process (for this, I expect I would have to use a SQLQuery which includes SYSDATE as the EventTemplate, but would I have to query SYSDATE out of the space every time I want to update the object rather than using System.currentTimeMillias or equivalent, in order to ensure I am comparing apples to apples?)
Applying a configuration setting of some kind on the blocked event polling container or listener that causes it to only poll periodically.
You can use both approach:
docs.gigaspaces.com/xap97/polling-container.html#dynamic-template-definition
docs.gigaspaces.com/sbp/dynamic-polling-container-templates-using-triggeroperationhandler.html
In the future, for GigaSpaces related questions, please use:
ask.gigaspaces.org/questions/
Thanks,
Ester.
I have converted the Starbucks example to use RabbitMQ and NHibernate.. However, there is a bug/challenge/issue with the DrinkPreparationSaga and when it actually gets saved to the database vs. when the PaymentCompleteMessage gets submitted.
How the code works (out of the box, this isn't anything I changed)... The new instance of the saga isn't saved to the database until AFTER the Initial state completes and it transitions to its next state.
The problem is that in the sample Starbucks application the DrinkPreparationSaga starts off with a very slow method that prints out coffee making sounds once every 1 a second 10 times..
So there is 10 seconds between when the Saga is actually created and when its saved to the database.. The bigger problem with that is, that any other messages that are destined to that instances of the saga (by CorrolationId) are thrown in the error queue because the Saga doesn't exist.
Shouldn't the NHibernateSagaRepository immediately save the new Saga Instance, then run the workflow, then update the saga post workflow? I can't seem to think of another way to make the example work, but that would require a decent bit of reorganizing in the NHibernateSagaRepository.
Thanks in advance.
The reason sagas are not saved before processing the message is that some members of the saga may not be nullable (or allow nulls) and they are not set before the initial saga message is processed.
And you're correct. Take a look at the Riktig sample (http://github.com/phatboyg/Riktig) to see how the Automatonymous sagas are used and how the correlation of another service (in this case, the image retrieval service) is used. Sagas should not actually perform work, but coordinate the state of a transaction. The earlier Starbucks example was a naive implementation that we built one morning in Austin. It is long overdue for an update (for more reasons, including that it still uses Magnum state machines, which are soon deprecated in favor of Automatonymous).