Getting Started
Introduction
9 • Task Scheduler

The Task Scheduler

Lune has a built-in task scheduler, which can let you run things at fixed intervals, ensure some work happens after everything else is already done, and more.

Spawning Tasks & Waiting

This example script will run several tasks concurrently, in lightweight Lua threads, also known as coroutines:

local task = require("@lune/task")
 
print("Hello, scheduler!")
 
task.spawn(function()
	print("Spawned a task that will run instantly but not block")
	task.wait(2)
	print("The instant task resumed again after 2 seconds")
end)
 
print("Spawning a delayed task that will run after 5 seconds")
 
task.delay(5, function()
	print("Waking up from my deep slumber...")
	task.wait(1)
	print("Hello again!")
	task.wait(1)
	print("Goodbye again! 🌙")
end)

Deferring Work

This example script runs a bit of work after all other threads have finished their work or are yielding waiting for some other result:

local task = require("@lune/task")
 
task.defer(function()
	print("All the scheduled work has finished, let's do some more!")
	local a = 0
	for _ = 1, 100000 do
		local b = a + 1
	end
	print("Phew, that was tough.")
end)
 
print("Working...")
local s = ""
for _ = 1, 5000 do
	s ..= ""
end
print("Done!")

Advanced Usage & Async

Spawning tasks like this can be very useful together with asynchronous APIs from other built-in libraries, such as net.request:

local net = require("@lune/net")
local task = require("@lune/task")
 
local completed = false
task.spawn(function()
	while not completed do
		print("Waiting for response...")
		task.wait() -- Wait the minimum amount possible
	end
	print("No longer waiting!")
end)
 
print("Sending request")
net.request("https://google.com")
print("Got response")
 
completed = true
Bonus

Barebones Signal Implementation

Using the task library, it becomes trivial to implement signal objects that take callbacks to run when a signal is fired, and that can handle both synchronous and yielding (async) callbacks without additional complexity:

local task = require("@lune/task")
 
local function newSignal()
	local callbacks = {}
 
	local function connect(callback: (...any) -> ())
		table.insert(callbacks, callback)
	end
 
	local function fire(...: any)
		for _, callback in callbacks do
			task.spawn(callback, ...)
		end
	end
 
	return connect, fire
end
 
local connectToThing, fireThing = newSignal()
 
connectToThing(function(value)
	print("Callback #1 got value:", value)
	task.wait(1)
	print("Callback #1 still has value:", value)
end)
 
connectToThing(function(value)
	print("Callback #2 got value:", value)
	task.wait(0.5)
	print("Callback #2 still has value:", value)
end)
 
print("Before firing")
fireThing(123)
print("After firing")
 
--> Before firing
--> Callback #1 got value: 123
--> Callback #2 got value: 123
--> After firing
--> ...
--> Callback #2 still has value: 123
--> ...
--> Callback #1 still has value: 123