Workflow Schedule Template
The Workflow Schedule template demonstrates how BindAI represents time-based workflow schedules and checks whether they are due. AWorkflowSchedule stores:
- The workflow identifier
- The next scheduled execution time
- An optional recurring interval
- Whether the schedule is enabled
WorkflowScheduler keeps schedules in memory, identifies enabled schedules that are due, and advances a schedule’s next-run time by its configured interval.
Scheduling is separate from workflow execution. The scheduler determines when a workflow is due; application code is responsible for starting the workflow and managing the scheduling lifecycle.
The current implementation provides scheduling primitives, not a complete background scheduling service.
Purpose
This template demonstrates how to:- Create a workflow schedule
- Register schedules with a scheduler
- Check which schedules are due
- Configure recurring intervals
- Enable or disable schedules
- Advance recurring schedules after processing
- Understand the current limitations of in-memory scheduling
Scheduling Architecture
The scheduling components provide timing state and due-checking:WorkflowSchedule
AWorkflowSchedule is a dataclass describing when a workflow should execute.
For example:
There is no additional recurrence-rule object in the current implementation.
Registering a Schedule
Create aWorkflowScheduler and add schedules with add():
add() method does not return the schedule. Multiple schedules can be added to the same scheduler.
In-Memory Scheduler
The current scheduler stores schedules in an in-memory list:- Database persistence
- File persistence
- Distributed scheduling
- Scheduler recovery after process restart
- A persistent schedule store
- A background scheduler thread
- A built-in scheduler service
Checking Due Schedules
The scheduler provides:schedule.enabledisTrue.schedule.next_run <= datetime.now(UTC).
next_run so they can be compared with the scheduler’s current UTC time.
Calling due() does not automatically mark schedules as processed, advance their timestamps, or execute their workflows.
Due Schedule Example
Suppose the scheduler contains these schedules, with times expressed in UTC:next_run is at or before the current UTC time.
This example assumes that the listed times fall on the same date and that the schedules have not been advanced or otherwise modified.
Enabled Schedules
Schedules are enabled by default:enabled defaults to True, the schedule can be returned by:
next_run time has arrived.
You can also explicitly enable a schedule:
Disabled Schedules
A schedule can be disabled:due().
Even if:
One-Time Schedules
A schedule with no recurring interval can represent a one-time execution:due() returns it.
Calling:
next_run because no interval is configured.
The scheduler does not automatically disable or remove a one-time schedule.
If application code calls due() again after the scheduled time has passed, the same enabled schedule can be returned again.
For one-time application behavior, application code should disable or otherwise manage the schedule after processing it:
Recurring Schedules
A recurring schedule specifies an interval:
The scheduler does not interpret calendar recurrence rules such as:
- Every Monday
- The first day of every month
- Weekdays at 09:00
next_run by the configured number of seconds.
Rescheduling
The scheduler provides:timedelta to the existing timestamp:
Rescheduling Without an Interval
If:next_run.
For example:
Zero Interval
The current implementation checks the interval using truthiness:Missed Recurring Schedules
reschedule() advances next_run by one interval only.
For example:
due() can return the schedule again.
Application code is responsible for deciding how missed executions should be handled. Possible strategies include processing each missed interval, skipping missed intervals, or advancing directly to the next future run time. Those strategies are not implemented by the scheduler itself.
Scheduler Lifecycle
A typical application-level scheduling loop looks like:WorkflowScheduler provides these core operations:
- When to call
due() - How to execute due workflows
- When to call
reschedule() - How to handle workflow failures
- How to handle missed schedules
- How frequently to poll
- How to prevent duplicate or overlapping executions if required
Scheduler Does Not Execute Workflows
WorkflowScheduler does not invoke WorkflowExecutor.
Its responsibility is to identify schedules that are due and update schedule timestamps when requested.
The separation is:
workflow_id to the appropriate workflow and initiate execution.
This keeps scheduling state separate from workflow execution.
Scheduler vs Workflow Executor
The two components have different responsibilities.
The scheduler answers:
When is this workflow due?The executor answers:
How does this workflow execute?Application code connects these responsibilities.
Scheduler vs Workflow Loop
Scheduling and workflow loops both support repeated behavior, but at different levels.
A scheduler helps determine when a workflow may start.
A loop determines how a running workflow repeats.
Example: Hourly Workflow
An application can register an hourly workflow schedule:workflow_id to a workflow or execute it automatically.
Multiple Schedules
A single scheduler can contain multiple schedules:next_run is at or before the current UTC time is included in the returned list.
The scheduler does not check whether multiple schedules refer to the same workflow or whether that workflow is already running.
Current Time Handling
The current implementation uses:WorkflowScheduler.due().
Therefore, due() compares each schedule’s next_run against a timezone-aware UTC datetime.
Applications should supply compatible timezone-aware next_run values.
Mixing naive and timezone-aware datetimes can cause Python datetime comparisons to raise an exception. Use consistent UTC timestamps to avoid this issue.
The scheduler does not currently provide:
- Timezone conversion
- Local-time scheduling rules
- Daylight-saving-time handling
- Calendar-based recurrence
- User timezone configuration
Timezone Considerations
The scheduler uses UTC for its due-time comparison and advances the storednext_run by a duration.
For example:
Recurring Execution
Recurring schedules use a fixed interval. For example:Schedule State
A schedule contains four pieces of state:- Last-run timestamp
- Run count
- Failure count
- Execution result
- Retry state
- Schedule history
No Duplicate Detection
The scheduler does not check whether a workflow is already registered. For example, application code can add multiple schedules with the sameworkflow_id:
due() evaluates them independently.
Applications should avoid registering duplicate schedules unintentionally and should implement deduplication if their use case requires it.
No Automatic Execution
The scheduler does not start a background thread or process. An application must actively call:Typical Use Cases
The scheduling primitives can support application-managed workflows such as:- Periodic reports
- Recurring data synchronization
- Scheduled document processing
- Knowledge refreshes
- Recurring maintenance
- Automated backups
- Monitoring workflows
- Periodic AI processing
Scheduling and Workflow Execution
A complete application-level flow can look like:Error Handling
The current scheduler does not execute workflows, so it does not manage workflow execution errors. If application code starts a workflow and that workflow fails, the application is responsible for deciding whether and when to reschedule the associated schedule. The scheduler does not implement:- Retry policies for workflow executions
- Backoff
- Workflow failure handling
- Dead-letter behavior
- Execution cancellation
- Automatic rescheduling after failure
Persistence and Recovery
Schedules are stored only in memory:Best Practices
- Use timezone-aware UTC values for
next_run. - Prefer positive
interval_secondsvalues for recurring schedules. - Explicitly disable one-time schedules after processing if they should not run again.
- Decide whether to reschedule recurring schedules after success, failure, or both.
- Define how missed intervals should be handled.
- Keep scheduling separate from workflow execution.
- Avoid registering duplicate schedules unintentionally.
- Do not assume the scheduler persists schedules.
- Do not assume the scheduler executes workflows automatically.
- Handle workflow failures separately from schedule management.
- Use application-level infrastructure for polling or background scheduling.
- Design recurring workflows so repeated execution is safe.
- Add locking or deduplication if multiple application workers might process the same schedule.
Related Templates
The Schedule template relates to:08.3 workflow-loop.md08.4 workflow-parallel.md08.6 workflow-retry.md08.7 workflow-timeout.md
Current Limitations
The currentWorkflowScheduler is intentionally simple.
It does not currently provide:
- Persistent schedules
- Background polling
- Distributed scheduling
- Scheduler workers
- Timezone conversion or local-time recurrence
- Calendar recurrence rules
- Automatic workflow execution
- Automatic retries
- Missed-run recovery
- Schedule history
- Duplicate detection
- Scheduler locking
- Distributed coordination
Summary
The Workflow Schedule template demonstrates how BindAI represents and checks time-based workflow schedules.WorkflowSchedule stores:
WorkflowScheduler provides three core operations:
add()stores schedules in memory.due()returns enabled schedules whosenext_runis at or before the current UTC time.reschedule()advances a schedule by one configured interval wheninterval_secondsis truthy.
