Self-Dispatching Laravel Queues: Orchestrating a Telegram Bingo Bot

Overview

Managing real-time game logic requires a delicate balance between immediate response and scheduled automation. This implementation uses

Laravel Queues
to drive a
Telegram
bingo bot. Instead of relying on traditional cron jobs which lack granular timing, we utilize delayed dispatching and self-perpetuating jobs to handle game phases like player registration and number drawing. This approach ensures the server remains responsive while background workers handle the heavy lifting of game state management.

Prerequisites

To implement this pattern, you should be comfortable with:

  • Laravel Framework: Basic understanding of Services and Controllers.
  • Queue Workers: Knowledge of how to run php artisan queue:work.
  • Telegram Bot API: Familiarity with webhooks and command handling.
  • Database Management: Experience with migrations and basic CRUD operations.

Key Libraries & Tools

  • Laravel Queues
    : The core engine for background job execution.
  • Filament Admin Panel
    : An admin panel used to trigger game sessions and configure parameters.
  • Laravel Forge
    : Used for server management and maintaining the queue worker process.
  • Database Driver: The chosen queue driver for persistence and reliability.

Code Walkthrough

Self-Dispatching Laravel Queues: Orchestrating a Telegram Bingo Bot
Laravel Queues Example: Telegram Bot with Self-Dispatching Jobs

The Initial Delay

When a game starts, we dispatch a job to close the registration window after a specific interval.

// In GameLifeCycleService.php
CompleteJoinPeriod::dispatch($game)->delay(now()->addSeconds($game->join_seconds));

This line instructs the queue to wait exactly $X$ seconds before moving the game from 'joining' to 'active' status.

Recursive Self-Dispatching

Once the game is active, the DrawNumber job handles the logic of pulling a number and then queues its own successor.

public function handle()
{
    // 1. Draw and notify
    $this->drawAndSendMessage();

    // 2. Check termination condition
    if ($this->game->draws->count() >= 75) {
        return; // Stop the cycle
    }

    // 3. Self-dispatch with delay
    self::dispatch($this->game->fresh())
        ->delay(now()->addSeconds(5));
}

By calling self::dispatch() within the handle method, the job creates a loop. It executes, waits 5 seconds, and executes again until 75 numbers are drawn or a player claims bingo.

Syntax Notes

  • Fresh Models: Always use $model->fresh() when dispatching to ensure the next job has the most recent database state.
  • Delay Method: The delay() helper accepts a DateTime or Carbon instance to set execution timing.
  • Termination Returns: Simply returning from the handle method without dispatching prevents the next cycle from starting.

Practical Examples

  • Auction Countdowns: Triggering a "Going once, going twice" sequence after a bid.
  • Drip Campaigns: Sending a series of onboarding emails spaced 24 hours apart.
  • Status Monitoring: Checking an external API status every minute until a specific result returns.

Tips & Gotchas

  • Queue Workers: Ensure your queue worker is running as a daemon. On
    Laravel Forge
    , set up a process to keep the worker active.
  • Database Locks: When multiple jobs or webhooks might update the same game record (like a /bingo command during a draw), use lockForUpdate() to prevent race conditions.
  • Memory Leaks: Since these jobs can loop many times, avoid heavy static caching within the job class.
Self-Dispatching Laravel Queues: Orchestrating a Telegram Bingo Bot

Fancy watching it?

Watch the full video and context

3 min read