roblox-aurora / rbx-net

Advanced multi-language networking framework for Roblox
https://rbxnet.australis.dev/
MIT License
94 stars 12 forks source link

Dropped requests from middleware remain in 'Started' state for AsyncFunctions. #77

Open niko284 opened 2 years ago

niko284 commented 2 years ago

When calling the server with a ServerAsyncFunction, there's a possibility that your middleware may not propagate your request and finish it. For a client that is awaiting the promise's fate, the promise never settles.

This can be reproduced by making a middleware that rejects all requests and hooking a :finally() method to your promise. It will never reach it.

Vorlias commented 2 years ago

What version of Net are you using, perchance?

Vorlias commented 2 years ago

Also do you have an example of a middleware which triggers this behaviour + some example client call code to go with it?

niko284 commented 2 years ago

I am currently on vorlias/net@3.0.1 on Wally. Here is an example::

Client sided code:

UseItem:CallServerAsync()
    :andThen(function(networkResponse: Types.NetworkResponse)
        if networkResponse.Success == false then
            warn(networkResponse.Response)
            -- Let's rollback the state, so the item is back in the inventory, since the server didn't accept it.
            props.addItem(item)
        end
    end)
    :finally(function()
        print("settled")
    end)

Server sided middleware:

-- Deserializer
-- August 27th, 2022
-- Nick

-- // Variables \\

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Constants = ReplicatedStorage.constants
local Types = require(Constants.Types)

local Deserializer = {}

local function DeserializerMiddleware(deserializers: { Types.Serializer })
    return function(next, _instance)
        return function(player, ...)
            return error("no")
        end
    end
end

Deserializer.__call = function(_, ...)
    return DeserializerMiddleware(...)
end

return setmetatable({}, Deserializer)

An error is always returned by my middleware and next() is never called, for an easy repro case. My :finally() method that is attached to my promise is never called, and 'settled' never prints.

Here is the output to a UseItem call:

image