prefect server in zig

timestamp handling in prefect#

status: mostly resolved. next_scheduled_start_time added, timestamp parsing works. preserved as reference for python/zig differences and .serve() vs workers distinction.

python implementation#

storage#

  • PostgreSQL: TIMESTAMP(timezone=True) - native timezone-aware
  • SQLite: DATETIME() naive, manually converts to/from UTC

format#

all timestamps are UTC timezone-aware. JSON serialization uses ISO 8601:

2024-01-22T15:30:45.123456+00:00

key fields for flow_run#

  • expected_start_time - when the run was originally scheduled
  • next_scheduled_start_time - used for scheduling queries (we're missing this!)
  • start_time - actual start
  • end_time - actual end
  • state_timestamp - when state last changed

get_scheduled_flow_runs query#

WHERE fr.state_type = 'SCHEDULED'
  AND fr.next_scheduled_start_time <= :scheduled_before
ORDER BY fr.next_scheduled_start_time ASC

our implementation#

storage#

  • SQLite: TEXT with format 2024-01-22T15:30:45.123456Z
  • using SQLite strftime('%Y-%m-%dT%H:%M:%fZ', 'now') for defaults

issues (resolved)#

  1. missing next_scheduled_start_time ✓ added to flow_run table

  2. string comparison is fragile ✓ timestamp parsing handles multiple formats

  3. bandaid fix - normalizing client timestamps (space→T, +00:00→Z) works and is acceptable

.serve() vs workers#

.serve() (Runner)#

  • creates deployment, starts local polling loop
  • calls POST /deployments/get_scheduled_flow_runs every N seconds
  • executes flows locally in the same process
  • NOT a worker

workers#

  • standalone daemon process
  • connects to work pools/queues
  • work pool workers: POST /work_pools/{name}/get_scheduled_flow_runs
  • task workers: WebSocket WS /task_runs/subscriptions/scheduled

we test#

  • test_cron_scheduler - server-side scheduler creates runs (correct)
  • test_worker_execution - mislabeled! tests .serve() Runner, not a worker
  • test_serve_with_schedule - verifies deployment has schedule attached (correct)