Daravelv1.0.0
ENID GitHub

Cache, events, queues and scheduling

final total = await Cache.remember(
  'posts.count',
  const Duration(minutes: 5),
  () => Post.query().count(),
);

await Event.dispatch(const PostPublished(1));
await Queue.dispatch(const PublishPost(1)).onQueue('posts');

Cache#

Stores: memory (per isolate, LRU), process (shared by every isolate of the server through the coordinator), file and database (Laravel's cache table). Cache.remember, flexible (stale-while-revalidate), increment, pull, lock (atomic locks, fail closed) mirror Laravel.

Events#

Event.listen<OrderShipped>((event) async {...}) or listener classes in bootstrap/listeners.dart. Event.dispatchAfterCommit waits for the current transaction. Queued listeners run through the queue.

Queues#

final class PublishPost extends Job {
  const PublishPost(this.postId);

  final int postId;

  @override
  String get jobName => 'publish-post';

  @override
  Map<String, Object?> toJson() => {'post_id': postId};

  @override
  Future<void> handle(JobContext ctx) async {
    final post = await Post.query().findOrFail(postId);
    await post.update({'published': true});
  }
}

Jobs are registered by name in bootstrap/jobs.dart (JobDefinition('publish-post', (json) => PublishPost(...))), because Daravel does not use reflection. Drivers: sync, database (Laravel's jobs / failed_jobs tables) and memory. Retries, backoff, timeouts, unique jobs, job middleware, queue:work, queue:failed, queue:retry and queue:restart are supported. Dispatch inside a transaction is deferred until commit by default.

For monitoring and operations (the hooks a Horizon-style dashboard builds on):

  • List<String> get tags on a job (for example ['user:42']) is stored in the payload's tags key.
  • Queue.connection().oldestWait('emails') says how long the oldest ready job has been waiting.
  • dartisan queue:pause database:emails stops every worker taking jobs from that queue (running jobs finish) until dartisan queue:continue database:emails; QueueWorker.pause() / resume() do the same for one worker.

Scheduling#

routes/console.dart declares the schedule:

void consoleRoutes(Schedule schedule) {
  schedule.command('reports:send').dailyAt('13:00').onOneServer();
  schedule.job(const PruneTokens()).hourly().withoutOverlapping();
}

Run it with schedule:work (long-running) or schedule:run from cron; schedule:list shows the next runs.