Task Queueing Module

Task Queue Module

:link: https://create.roblox.com/store/asset/18332916329

Overview

The TaskQueue module is designed to manage and execute tasks sequentially in Roblox. This is particularly useful in scenarios where tasks must be performed one at a time to avoid conflicts, ensure order, or manage resources effectively. The module allows you to enqueue functions (tasks) along with their arguments, ensuring that each task completes before the next one starts.

Module Script

Here’s the TaskQueue module script, which should be placed in ServerScriptService:

-- ModuleScript in ServerScriptService

local TaskQueue = {}
TaskQueue.__index = TaskQueue

function TaskQueue.new()
    local self = setmetatable({}, TaskQueue)
    self._queue = {}
    self._size = 0
    self._processing = false
    return self
end

function TaskQueue:Enqueue(taskFunction, ...)
    local args = {...}
    table.insert(self._queue, function()
        taskFunction(unpack(args))
    end)
    self._size = self._size + 1
    self:ProcessQueue()
end

function TaskQueue:Dequeue()
    if self._size == 0 then
        error("Queue is empty")
    end
    local task = table.remove(self._queue, 1)
    self._size = self._size - 1
    return task
end

function TaskQueue:ProcessQueue()
    if not self._processing and self._size > 0 then
        self._processing = true
        coroutine.wrap(function()
            while self._size > 0 do
                local task = self:Dequeue()
                task()
            end
            self._processing = false
        end)()
    end
end

function TaskQueue:Size()
    return self._size
end

function TaskQueue:IsEmpty()
    return self._size == 0
end

function TaskQueue:Clear()
    self._queue = {}
    self._size = 0
end

return TaskQueue

How to Use the Task Queue Module

  1. Require the Module: First, require the module in your script.
  2. Create a Task Queue Instance: Instantiate a new task queue.
  3. Enqueue Tasks: Add tasks to the queue using the Enqueue method.
  4. Process Tasks: The module automatically processes tasks in the order they were added.

Example Usage

Here’s an example of how to use the TaskQueue module in a script:

-- Script in ServerScriptService

local TaskQueue = require(game.ServerScriptService:WaitForChild("TaskQueue"))
local myQueue = TaskQueue.new()

-- Define some tasks
local function Task1()
    print("Starting Task 1")
    wait(2)
    print("Completed Task 1")
end

local function Task2(arg1, arg2)
    print("Starting Task 2 with arguments:", arg1, arg2)
    wait(3)
    print("Completed Task 2")
end

local function Task3()
    print("Starting Task 3")
    wait(1)
    print("Completed Task 3")
end

-- Enqueue tasks with arguments
myQueue:Enqueue(Task1)
myQueue:Enqueue(Task2, "Hello", "World")
myQueue:Enqueue(Task3)

-- The tasks will be processed in order

In this example:

  • Task1: A simple task that prints messages and waits for 2 seconds.
  • Task2: A task that prints messages with arguments and waits for 3 seconds.
  • Task3: Another simple task that prints messages and waits for 1 second.

The tasks are enqueued and will be executed in the order they were added. Task1 will complete before Task2 starts, and Task2 will complete before Task3 starts.

Use Case Examples

  1. Order Processing System: If you’re developing a game with an order processing system, you might want to ensure that orders are processed one at a time to avoid race conditions or data inconsistencies.

    local function ProcessOrder(orderId)
        print("Processing order:", orderId)
        wait(2) -- Simulate processing time
        print("Order processed:", orderId)
    end
    
    myQueue:Enqueue(ProcessOrder, 1)
    myQueue:Enqueue(ProcessOrder, 2)
    myQueue:Enqueue(ProcessOrder, 3)
    
  2. Sequential Animations: When creating a sequence of animations or events that should play one after another, the task queue ensures they don’t overlap.

    local function PlayAnimation(animation)
        print("Playing animation:", animation.Name)
        wait(animation.Length) -- Simulate animation length
        print("Animation completed:", animation.Name)
    end
    
    local anim1 = {Name = "Jump", Length = 1}
    local anim2 = {Name = "Run", Length = 2}
    local anim3 = {Name = "Wave", Length = 1.5}
    
    myQueue:Enqueue(PlayAnimation, anim1)
    myQueue:Enqueue(PlayAnimation, anim2)
    myQueue:Enqueue(PlayAnimation, anim3)
    
  3. Resource Management: If your game has limited resources (like spawning limited entities), you can use a task queue to ensure resource creation is handled properly.

    local function SpawnEntity(entityType)
        print("Spawning entity:", entityType)
        wait(1) -- Simulate spawning time
        print(entityType, "spawned")
    end
    
    myQueue:Enqueue(SpawnEntity, "Zombie")
    myQueue:Enqueue(SpawnEntity, "Skeleton")
    myQueue:Enqueue(SpawnEntity, "Dragon")
    

Roblox provides built-in mechanisms for handling coroutines and asynchronous tasks, but it doesn’t natively provide a high-level task queue system out of the box. Here’s a brief overview of Roblox’s native capabilities and why you might still want to use a custom task queue module:

Doesn’t Roblox already support coroutines natively?

  1. Coroutines: Roblox uses Lua, which supports coroutines natively. Coroutines allow for cooperative multitasking by yielding execution and resuming later.

    local function exampleCoroutine()
        print("Coroutine started")
        wait(2)
        print("Coroutine resumed after wait")
    end
    
    local co = coroutine.create(exampleCoroutine)
    coroutine.resume(co)
    
  2. Promises: Roblox also provides the Promise library through Promise.new, which allows for managing asynchronous tasks in a more structured way, similar to JavaScript’s Promise.

    local Promise = require(game.ReplicatedStorage.Promise)
    
    Promise.new(function(resolve, reject)
        wait(2)
        resolve("Task completed")
    end):andThen(function(result)
        print(result)
    end):catch(function(err)
        warn(err)
    end)
    

Why Use a Custom Task Queue Module?

While coroutines and promises are powerful, they require manual management of task flow. A custom task queue module abstracts this complexity and provides benefits such as:

  1. Sequential Task Execution: Ensures that tasks are executed one after another, without needing to manage coroutine states or promise chains manually.

  2. Task Management: Simplifies enqueuing, dequeuing, and processing tasks with arguments, making code more maintainable and readable.

  3. Error Handling: Centralizes error handling for all tasks, making it easier to manage and debug.

  4. Resource Management: Helps manage resources by ensuring tasks are not started until the previous ones are completed, preventing race conditions and resource conflicts.

Conclusion

The TaskQueue module is a robust solution for managing sequential tasks in Roblox. By encapsulating tasks and ensuring they are processed one at a time, you can maintain order and prevent conflicts in various scenarios. This module is versatile and can be adapted to numerous use cases, from simple print statements to complex game mechanics.

If you have any questions at all, absolutely feel free to ask and I will answer to the best of my ability.

Edit: I do plan on adding the ability to iterate through tables of functions. For the time being just make the table yourself and insert the functions and then just use a for loop to create the task for each one.

14 Likes

this seems very helpful! i will prob use this one way or another, one thing I’d like to be added is just a function to queue a table of multiple tasks, maybe just so the code looks cleaner, thanks!

1 Like

you should change self._size = self._size + 1 to self._size += 1 and self._size -= 1 respectively.

1 Like

Yeah, it’s funny you mentioned that because I actually noticed that and have already changed it :joy:

Can you explain a little more? I am assuming you mean a table of functions, not individual values, but I would appreciate any clarification.

yep exactly that, i hate the character limit(ignore)

image

btw we cant get it for some reason. might be offsale.

Fixed, thank you. I don’t know why but distribution was disabled.