Qbox-project / qbx_core

http://qbox-project.github.io
Other
45 stars 109 forks source link

Revamp queue #486

Open D4isDAVID opened 2 weeks ago

D4isDAVID commented 2 weeks ago

The problem

Ideal solution

Alternative solutions

No response

Additional context

No response

TransitNode commented 2 weeks ago

I might add to this that using coroutines together with a task queue could be very beneficial for a queue-system over a single while loop-thread. Since coroutines can be suspended and resumed, the queue-system can handle a large number of concurrent connections without the overhead of threads, but I must advise that multi-threading is almost always necessary for a queue system, in my opinion mixing threads with coroutines could achieve a good amount parallelism.

pseudo-code example:

-- Coroutine-based Queue System with Threads

-- Data structures
local queue = {} -- The main queue to store players
local taskQueue = {} -- Queue to hold coroutine tasks
local threadQueue = {} -- Queue to hold threads

-- Helper function to add a task to the queue
local function addTask(task)
    local co = coroutine.create(task) -- Create a new coroutine from the task function
    table.insert(taskQueue, co) -- Add the coroutine to the task queue
end

-- Helper function to add a thread to the queue
local function addThread(thread)
    table.insert(threadQueue, thread) -- Add the thread to the thread queue
end

-- Event loop for coroutines and threads
local eventLoop = coroutine.create(function()
    while true do
        local task = table.remove(taskQueue, 1) -- Get the next task from the task queue
        if task then
            local success, result = pcall(task) -- Execute the task using pcall to catch errors
            if success then
                local thread = coroutine.create(function()
                    for i = 1, #threadQueue do
                        local thread = threadQueue[i]
                        local success, err = pcall(thread) -- Execute each thread using pcall
                        if not success then
                            print("Error in thread: " .. err)
                        end
                    end
                    coroutine.yield(result) -- Yield the result of the coroutine task
                end)
                addThread(thread) -- Add the new thread to the thread queue
            else
                print("Error in thread: " .. result) -- Print the error if the task failed
            end
        else
            coroutine.yield() -- Yield control if no tasks available
        end
    end
end)

-- Dequeue function
local function dequeue()
    addTask(function()
        local threadCount = #threadQueue -- Get the number of threads in the queue
        if threadCount > 0 then
            for i = 1, threadCount do
                local thread = threadQueue[i]
                local success, result = pcall(thread) -- Execute each thread using pcall
                if success then
                    print("Thread success: " .. result) -- Print the result if the thread succeeded
                else
                    print("Thread error: " .. result) -- Print the error if the thread failed
                end
            end
        else
            print("No threads to execute") -- Print a message if there are no threads to execute
        end
    end)
end

Another suggestion is to add a player reservation system, so that users can reserve slots for important people, encase of an ingame event or such.

Instead of having a fixed set of sub-queues with predefined priorities, a new queue function could dynamically prioritize players based on various factors such as playtime or anything else the user might want configure. Give weights to each factor. Ofc keeping the fixed sub-set queue system would be a good idea, but having a configuration choice to pick which system to use is always a favourable outcome.

D4isDAVID commented 2 weeks ago

Thanks for the suggestions.

I want to clarify that implementing the points system will be done in a way where all of that is possible with the correct configuration. It will be replacing the sub-queue system completely but it I'll do it in a way where it's possible to replicate the functionality.

Manason commented 2 weeks ago

Stepping back to talk about queuing at a high level, I haven't reviewed the queue code in a while. What computation does the server need to do concurrently? My suspicion is that concurrency is not needed, as even updating 10k players in the queue synchronously should take O(ms)