Skip to content

Events: add absolute-time schedule trigger #3343

@ocs-agent

Description

@ocs-agent

Summary

The events framework currently supports two trigger types:

  • StaticTrigger — fires on a discrete event (conversation start/end, new message, participant joined, etc.)
  • TimeoutTrigger — fires after a relative delay from some anchor point (last message, first message, inactivity)

Neither supports firing at a specific absolute datetime. This is a gap for use-cases like:

  • "Send a follow-up message to all participants on 2025-06-01 at 09:00"
  • "End conversations that haven't completed by a deadline"
  • Study or programme cohorts where events must fire at fixed calendar dates regardless of when each session started

Proposed new trigger type: ScheduledTrigger

A new model alongside StaticTrigger and TimeoutTrigger that fires at an explicitly specified datetime.

Model fields (sketch)

Field Type Notes
experiment FK → Experiment
action OneToOne → EventAction same as existing triggers
scheduled_at DateTimeField the absolute UTC datetime to fire
timezone CharField optional display timezone for the UI
is_active BooleanField
is_archived BooleanField
working_version self FK versioning, consistent with other triggers

Scheduling / execution

  • A periodic Celery beat task (or an extension of the existing trigger_bot_message_task approach) polls for ScheduledTrigger instances whose scheduled_at <= now and is_active=True and haven't already fired.
  • Alternatively, use django-celery-beat to create a one-shot PeriodicTask when the trigger is saved, and delete it after firing.
  • Firing behaviour is identical to existing triggers: instantiate the ACTION_HANDLERS handler for the action type and call invoke() for each eligible session.

Scope questions to resolve

  1. Per-session vs. per-experiment: does a ScheduledTrigger fire once globally (e.g. for all active sessions of an experiment) or is it pinned to a single session? The existing TimeoutTrigger is per-experiment-but-evaluated-per-session, which is probably the right model here too.
  2. Repeat / recurrence: out of scope for the first version — one-shot only.
  3. UI: a new row in the events table with a datetime picker instead of a delay input.
  4. Versioning: should follow the same VersionsMixin pattern as TimeoutTrigger.

Acceptance criteria

  • ScheduledTrigger model created with migration
  • Admin registration
  • Celery task that fires due triggers and logs results via EventLog
  • Create / edit / delete UI in the events section
  • The trigger is included in experiment versioning / copy
  • Tests covering: trigger fires at the right time, does not double-fire, respects is_active

Metadata

Metadata

Assignees

No one assigned

    Labels

    good first issueIssues that can be taken by 3rd parties. Generally tasks that require less context / design.
    No fields configured for Feature.

    Projects

    Status

    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions