Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ZTzTopia/GTProxy/llms.txt

Use this file to discover all available pages before exploring further.

Overview

The scheduler global allows you to schedule tasks to run after a delay or at regular intervals. All time values are in milliseconds.

Scheduling Tasks

One-Shot Tasks

scheduler.schedule
function
delay
number
required
Delay in milliseconds before executing the callback
callback
function
required
Function to execute after the delay
Schedule a callback to run once after a specified delay.Returns a task ID that can be used to cancel the task.
local task_id = scheduler.schedule(1000, function()
    logger.info("This runs once after 1 second")
end)

Periodic Tasks

scheduler.schedule_periodic
function
interval
number
required
Interval in milliseconds between executions
callback
function
required
Function to execute repeatedly. Must return true to continue, false to stop.
initial_delay
number
Optional initial delay before first execution (defaults to interval)
Schedule a callback to run repeatedly at a fixed interval.Returns a task ID that can be used to cancel the task.
local task_id = scheduler.schedule_periodic(500, function()
    logger.info("This runs every 500ms")
    return true  -- Continue running
end)

Periodic with Initial Delay

local task_id = scheduler.schedule_periodic(1000, function()
    logger.info("Runs every 1s, starts after 2s")
    return true
end, 2000)  -- 2000ms initial delay

Task Management

Cancel Task

scheduler.cancel
function
task_id
number
required
The task ID returned by schedule() or schedule_periodic()
Cancel a specific pending task.
scheduler.cancel(task_id)

Cancel All Tasks

scheduler.cancel_all
function
Cancel all pending tasks.
scheduler.cancel_all()
logger.info("All tasks cancelled")

Check if Task is Pending

scheduler.is_pending
function
task_id
number
required
The task ID to check
Returns true if the task is still pending (not executed or cancelled).
if scheduler.is_pending(task_id) then
    logger.info("Task is still pending")
end

Get Pending Task Count

scheduler.pending_count
function
Returns the number of pending tasks.
local count = scheduler.pending_count()
logger.info("There are {} pending tasks", count)

Examples

Simple Delay

logger.info("Starting...")

scheduler.schedule(1000, function()
    logger.info("1 second has passed")
end)

Periodic Timer

local tick_count = 0

local task_id = scheduler.schedule_periodic(1000, function()
    tick_count = tick_count + 1
    logger.info("Tick #{}", tick_count)
    
    if tick_count >= 10 then
        logger.info("Stopping after 10 ticks")
        return false  -- Stop the timer
    end
    
    return true  -- Continue running
end)

Delayed Message

command.register("remind", "Set a reminder", function(ctx)
    if #ctx.args < 2 then
        ctx:reply("Usage: /remind <seconds> <message>")
        return false
    end
    
    local seconds = tonumber(ctx.args[1])
    if not seconds then
        ctx:reply("`4Error: ``Invalid time")
        return false
    end
    
    local message = table.concat(ctx.args, " ", 2)
    
    scheduler.schedule(seconds * 1000, function()
        local log = LogPacket.new()
        log.msg = "`2[Reminder] ``" .. message
        send.to_client(log)
    end)
    
    ctx:reply("`2Reminder set for {} seconds", seconds)
    return true
end)

Position Tracker

local tracking = false
local track_task_id = nil

command.register("track", "Toggle position tracking", function(ctx)
    if tracking then
        scheduler.cancel(track_task_id)
        tracking = false
        ctx:reply("`2Position tracking stopped")
    else
        track_task_id = scheduler.schedule_periodic(1000, function()
            local player = world:get_local_player()
            if player then
                logger.info("Position: ({}, {})", player.position.x, player.position.y)
            end
            return true
        end)
        
        tracking = true
        ctx:reply("`2Position tracking started")
    end
    
    return true
end)

Auto-Disconnect Timer

command.register("afk", "Auto-disconnect after time", function(ctx)
    if #ctx.args < 1 then
        ctx:reply("Usage: /afk <minutes>")
        return false
    end
    
    local minutes = tonumber(ctx.args[1])
    if not minutes or minutes <= 0 then
        ctx:reply("`4Error: ``Invalid time")
        return false
    end
    
    local seconds = minutes * 60
    
    scheduler.schedule(seconds * 1000, function()
        packet.send_text("action|quit", true)
        logger.info("Auto-disconnected after {} minutes", minutes)
    end)
    
    ctx:reply("`2Will disconnect in {} minutes", minutes)
    return true
end)

Countdown Timer

command.register("countdown", "Start a countdown", function(ctx)
    if #ctx.args < 1 then
        ctx:reply("Usage: /countdown <seconds>")
        return false
    end
    
    local seconds = tonumber(ctx.args[1])
    if not seconds or seconds <= 0 then
        ctx:reply("`4Error: ``Invalid time")
        return false
    end
    
    local remaining = seconds
    
    local task_id = scheduler.schedule_periodic(1000, function()
        ctx:reply("`2{} seconds remaining", remaining)
        
        remaining = remaining - 1
        
        if remaining < 0 then
            ctx:reply("`2Countdown finished!")
            return false
        end
        
        return true
    end)
    
    return true
end)

Task Manager

local tasks = {}

local function schedule(key, delay, fn)
    tasks[key] = scheduler.schedule(delay, fn)
    return tasks[key]
end

local function schedule_periodic(key, interval, fn, initial_delay)
    if initial_delay then
        tasks[key] = scheduler.schedule_periodic(interval, fn, initial_delay)
    else
        tasks[key] = scheduler.schedule_periodic(interval, fn)
    end
    return tasks[key]
end

command.register("tasks", "Show pending tasks", function(ctx)
    local count = scheduler.pending_count()
    ctx:reply("`2Pending tasks: ``{}", count)
    
    for key, task_id in pairs(tasks) do
        if scheduler.is_pending(task_id) then
            ctx:reply("`2  - ``{} (ID: {})", key, task_id)
        end
    end
    
    return true
end)

Cleanup on Disconnect

local active_tasks = {}

event.on("server:Disconnect", function(ctx)
    logger.info("Cancelling {} active tasks", #active_tasks)
    
    for _, task_id in ipairs(active_tasks) do
        scheduler.cancel(task_id)
    end
    
    active_tasks = {}
end)

event.on("server:Connect", function(ctx)
    local task_id = scheduler.schedule_periodic(5000, function()
        logger.info("Heartbeat")
        return true
    end)
    
    table.insert(active_tasks, task_id)
end)

Coroutine Integration

You can use Lua coroutines with the scheduler for async-style code:
function sleep(ms)
    local co = coroutine.running()
    scheduler.schedule(ms, function()
        coroutine.resume(co)
    end)
    coroutine.yield()
end

event.on("server:Connect", function()
    coroutine.wrap(function()
        logger.info("Connected!")
        sleep(1000)
        logger.info("1 second later!")
        sleep(1000)
        logger.info("2 seconds later!")
    end)()
end)

Best Practices

Always return a boolean from periodic tasks
scheduler.schedule_periodic(1000, function()
    -- Do work
    
    if should_stop then
        return false  -- Stop
    end
    
    return true  -- Continue
end)
Clean up tasks when they’re no longer needed
local task_id = scheduler.schedule_periodic(1000, function()
    return true
end)

-- Later, when done:
scheduler.cancel(task_id)
Store task IDs for later management
local tasks = {}

tasks.heartbeat = scheduler.schedule_periodic(5000, function()
    logger.info("Heartbeat")
    return true
end)

-- Later:
if scheduler.is_pending(tasks.heartbeat) then
    scheduler.cancel(tasks.heartbeat)
end
Be careful with very short intervalsVery short intervals (< 50ms) can cause performance issues:
-- May cause performance issues
scheduler.schedule_periodic(10, function()
    return true
end)

-- Better
scheduler.schedule_periodic(100, function()
    return true
end)

See Also

Events API

Use scheduler with events

Examples

More scheduler examples

Build docs developers (and LLMs) love