Zenaton white logo

Workflow waiting

Managing long-running workflows is one of best use-cases of Zenaton. It’s really easy to temporarily pause a workflow. You just need to execute the provided Wait class:

use Zenaton\Tasks\Wait;
const { Wait } = require("zenaton");
Zenaton::Tasks::Wait.new
Zenaton.tasks.wait.Wait()
task.Wait()

Wait Duration

If you need to wait two weeks between two tasks, just do

(new Wait())->weeks(2)->execute();
await new Wait().weeks(2).execute();
Zenaton::Tasks::Wait.new.weeks(2).execute
Zenaton.tasks.wait.Wait().weeks(2).execute()
task.Wait().Weeks(2).Execute()

Your workflow will magically wake up 2 weeks later (same time). You have numerous options to fine-tune your waiting duration:

MethodAction
->seconds(30)
.seconds(30)
.seconds(30)
.seconds(30)
.Seconds(30)
waits 30 seconds
->minutes(15)
.minutes(15)
.minutes(15)
.minutes(15)
.Minutes(15)
waits 15 minutes
->hours(2)
.hours(2)
.hours(2)
.hours(2)
.Hours(2)
waits 2 hours
->days(1)
.days(1)
.days(1)
.days(1)
.Days(1)
waits 1 day
->weeks(1)
.weeks(1)
.weeks(1)
.weeks(1)
.Weeks(1)
waits next week (same time)
->months(2)
.months(2)
.months(2)
.months(2)
.Months(2)
waits 2 months (same time)
->years(10)
.years(10)
.years(10)
.years(10)
.Years(10)
waits 10 years (same time)

These methods can be combined, e.g.,

(new Wait())->weeks(2)->hours(2)->minutes(15)->seconds(23)->execute();
await new Wait().weeks(2).hours(2).minutes(15).seconds(23).execute();
Zenaton::Tasks::Wait.new.weeks(2).hours(2).minutes(15).seconds(23).execute
Zenaton.tasks.wait.Wait().weeks(2).hours(2).minutes(15).seconds(23).execute()
task.Wait().Weeks(2).Hours(2).Minutes(15).Seconds(23).Execute()

will wait for exactly 14 days, 2 hours, 15 minutes and 23 seconds!

Wait Date

MethodAction
->timestamp(1522591200)
.timestamp(1522591200)
.timestamp(1522591200)
.timestamp(1522591200)
.Timestamp(1522591200)
waits until 1st of April 2018, 2PM UTC
->at("15:10:23")
.at("15:10:23")
.at('15:10:23')
.at('15:10:23')
.At("15:10:23")
waits until 3:10PM and 23 seconds
->dayOfMonth(12)
.dayOfMonth(12)
.day_of_month(12)
.day_of_month(12)
.DayOfMonth(12)
waits to next 12th day (same time)
->monday()
.monday()
.monday
.monday()
.Monday
waits to next Monday (same time)
->tuesday(1)
.tuesday(1)
.tuesday(1)
.tuesday(1)
.Tuesday(1)
waits to next Tuesday (same time)
->wednesday(2)
.wednesday(2)
.wednesday(2)
.wednesday(2)
.Wednesday(2)
waits to 2nd Wednesday (same time)
->thursday()
.thursday()
.thursday
.thursday()
.Thursday()
waits to next Thursday (same time)
->friday()
.friday()
.friday
.friday()
.Friday()
waits to next Friday (same time)
->saturday()
.saturday()
.saturday
.saturday()
.Saturday()
waits to next Saturday (same time)
->sunday()
.sunday()
.sunday
.sunday()
.Sunday()
waits to next Sunday (same time)

These methods can be combined, e.g.,

(new Wait())->monday()->at("8:00")->execute();
await new Wait().monday().at("8:00").execute();
Zenaton::Tasks::Wait.new.monday.at('8:00').execute
Zenaton.tasks.wait.Wait().monday().at('8:00').execute()
task.Wait().Monday().At("8:00").Execute()

will wait until next Monday at 8am.

If you are on Monday, at 7am, this will wait for an hour only. If you are on Monday, at 9am, it will wait for a week minus one hour.

If you want to define another timezone than the default one, just use the static timezone method, before launching any wait task. Eg.

Wait::timezone('Europe/Paris');
Wait.timezone("Europe/Paris");
Zenaton::Tasks::Wait.timezone ='Europe/Paris'
Zenaton.tasks.wait.Wait().set_timezone('Europe/Paris')
task.Wait().Timezone("Europe/Paris")

Wait for an Event

If you need to wait until an event occurs, it's as easy as

$event = (new Wait(UserActivatedEvent::class))->execute()
const event = await new Wait("UserActivatedEvent").execute();
event = Zenaton::Tasks::Wait.new(UserActivatedEvent).execute
event = Zenaton.tasks.wait.Wait(UserActivatedEvent).execute()
var event Event
task.Wait().ForEvent("UserActivatedEvent").Execute().Output(&event)

In this example, the workflow will stall up to receiving a UserActivatedEvent. Then event variable will contain the received event object.

Usually, you want to add a timeout, in order to ensure that the workflow will finish:

$event = (new Wait(UserActivatedEvent::class))->days(5)->execute()
const event = await new Wait("UserActivatedEvent").days(5).execute();
event = Wait.new(UserActivatedEvent).days(5).execute
event = Wait(UserActivatedEvent).days(5).execute()
var event Event
task.Wait().ForEvent("UserActivatedEvent").Days(5).Execute().Output(&event)

In this example, after 5 days, the execution of the workflow will be released, but the event will be null. You can use the same methods as above to define the duration or the date of this timeout.

If a workflow instance receives an event before the instructions to wait for it, then this event will only be handled by the OnEvent method. If you want to have a persistent event, you can do something like:

public function handle()
{
    ...

    if (! $this->event) {
        $this->event = (new Wait(UserActivatedEvent::class))->days(5)->execute();
    }
    ...
}

public function onEvent($event)
{
    if ($event instanceof AddressUpdatedEvent) {
        $this->event = $event;
    }
}
async handle() {
  ...
  if (!this.event) {
    this.event = await new Wait('UserActivatedEvent').days(5).execute();
  }
  ...
},
onEvent(name, data) {
  if (name === 'UserActivatedEvent') {
    this.event = event;
  }
}
def handle
  @event ||= Zenaton::Tasks::Wait.new(UserActivatedEvent).days(5).execute
end

def on_event(event)
  @event = event if event.is_a?(UserActivatedEvent)
end
def handle(self):
    self.event = Zenaton.tasks.wait.Wait(UserActivatedEvent).days(5).execute()


def on_event(self, event):
    if isinstance(event, UserActivatedEvent):
        self.event = event
func (w WorkflowType) Handle() (interface{}, error) {
    ...
    if w.Event != nil {
        task.Wait().ForEvent("UserActivatedEvent").Days(5).Execute(&w.Event);
    }
    ...
}

func (w WorkflowType) OnEvent(name string, data interface{}) {
    if name == "UserActivatedEvent" {
        w.Event = data
    }
}