-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add timeout support to the Agnostic RPC system #510
Comments
This requires some prototyping and expansion of the spec. I think the cleanest way to implement this is option 1. But that means modifying the JSON RPC messages structure which we are trying to avoid. Mind that if the timeout parameter is optional it shouldn't conflict with the normal structure. Think of it as extending the message structure. |
On the receiving side we should default to a value even if not set. Absolute timeout vs keep alive timeout. For streams it could default to null for absolute timeout. Keep alive timeout should be something that each rpc params sets up themselves. I'm just wondering how we would prevent any DoS and we should avoid providing infinite streams for agent service so that we don't allow any DoS between agents. |
This is comprised of a two stages.
The first taking maybe 1-2 days, while the 2nd is tedious given the amount of handlers so It could take 2-3 days. This could be done before or after the agent handler migration. |
I think this or QUIC should be tackled first. The agent rpc migration has to wait until quic is ready and I'd like to have this ready for testing. So this and quic then the agent handler migration. |
I'll start with the server side default timeouts. For this the following changes need to be made
|
For streams it must be possible to have a timeout as infinite or the timeout would be a keep alive applied to per-message.
13 Mar 2023 16:35:55 Brian Botha ***@***.***>:
I'll start with the server side default timeouts. For this the following changes need to be made
1. > Timeout parameter added to the handler classes so they can be set when defining the handler.
2. > Handlers now take a *TimedCancellable* context when they are called. Can we use the timed cancellable decorator here? How does that work with extended methods?
3. > The RPCServer will take a default timeout parameter. This should be a relatively large value to accommodate long running RPC handlers.
4. > When handling a stream we create the timeout and abort signal and pass it along to the handler. The value of the timeout should be the minimum out of the global default, handler default and the client provided value.
…
—
Reply to this email directly, view it on GitHub[#510 (comment)], or unsubscribe[https://github.com/notifications/unsubscribe-auth/AAE4OHPJ77AA3YD3LBWDFPDW36VNRANCNFSM6AAAAAAVOEGQM4].
You are receiving this because you commented.[Tracking image][https://github.com/notifications/beacon/AAE4OHPOP2LVZFGUYF5H2Z3W36VNRA5CNFSM6AAAAAAVOEGQM6WGG33NNVSW45C7OR4XAZNMJFZXG5LFINXW23LFNZ2KUY3PNVWWK3TUL5UWJTSXOKAUE.gif]
|
Now that I think about it. It makes sense for streams (non-unary rpc) that would use the timeout to mean per-message timeout.
13 Mar 2023 16:38:23 Roger Qiu ***@***.***>:
For streams it must be possible to have a timeout as infinite or the timeout would be a keep alive applied to per-message.
13 Mar 2023 16:35:55 Brian Botha ***@***.***>:
>
> I'll start with the server side default timeouts. For this the following changes need to be made
>
1. >> Timeout parameter added to the handler classes so they can be set when defining the handler.
2. >> Handlers now take a *TimedCancellable* context when they are called. Can we use the timed cancellable decorator here? How does that work with extended methods?
3. >> The RPCServer will take a default timeout parameter. This should be a relatively large value to accommodate long running RPC handlers.
4. >> When handling a stream we create the timeout and abort signal and pass it along to the handler. The value of the timeout should be the minimum out of the global default, handler default and the client provided value.
…>
> —
> Reply to this email directly, view it on GitHub[#510 (comment)], or unsubscribe[https://github.com/notifications/unsubscribe-auth/AAE4OHPJ77AA3YD3LBWDFPDW36VNRANCNFSM6AAAAAAVOEGQM4].
> You are receiving this because you commented.[Tracking image][https://github.com/notifications/beacon/AAE4OHPOP2LVZFGUYF5H2Z3W36VNRA5CNFSM6AAAAAAVOEGQM6WGG33NNVSW45C7OR4XAZNMJFZXG5LFINXW23LFNZ2KUY3PNVWWK3TUL5UWJTSXOKAUE.gif]
>
|
That's possible but a little more tricky. It requires some feed back compared to the easier method of creating the timeout and forgetting about it. |
The reason is because a timeout for the entire duration of a stream is kind of useless, we don't really have a situation where that would be useful. However a timeout for unary is ultimately intended to prevent DOS and agents that are just stuck. Therefore a similar reason should apply for streams, it should be a per-message timer. Furthermore:
On the client side, during any given call, the client can set one of the 3 values above. On the server side, it can do one of several things:
So therefore on the server side the number of configurations is a bit more sophisticated. You could say:
So that could mean a handler should be able to set a min and max timeout to provide a range. I'm actually not sure whether we even should have min/max, or just have a Furthermore, I'm also not sure if we even allow the client to "request" a timeout. Perhaps it makes more sense that timeouts can be set on both sides, but there's no actual negotiation. Here's an idea. Timeouts can be set on both sides, but they are only advisory to the other side.
|
I think the last idea is clearer... to do. And that is also applied per-message when in CS, DS, SS. As for timeout applied to replies from the client, let's address this later, it's not that important. |
@tegefaulkes the timed cancellable functions works by wrapping functions. It's a higher order function that wraps a lower order function. There are actually 2 ways:
The first way can only work if handlers are defined as methods in a class. Arrow functions or just plain exported functions can only use the HOF wrapper. See the tests for how to use it. |
BTW, there are 2 possible abortions.
You may want to create symbols specific to the 2nd case though. See how we did something similar in the |
If you're going to add a "default" timer to the RPC server class... you may need to have that as the 3 options: |
Two small problems with having the timer reset after every sent message.
To address 1 for now i'm going to make a |
As for the timeout delays we can set. for the handlers I'm going with |
I can refresh the timer but since the timestamp and scheduled are |
Does the |
However beware of what happens if the timer is already activated? I think the call should fail. Since if you reset the timer it could mean the designated function is called twice. The |
You mean on every received message right? Not on every sent message. |
For the raw handlers you can reset the timer upon every byte of data. Actually that may end up being a bit slow. Ideally you can just update a property. But I think that's what your function does anyway. Its a keep alive timer at this point in time. |
Ok instead of updating upon EVERY byte of data. You want to update when a "block" is received. That's how must sockets work. So a block could be 1 byte, it could be 64 bytes... etc. |
The timer is available in the context that is provided to the raw handler. I was planning to just have the raw handler implement it's timer refresh logic. I'm hesitant to refresh on the raw I'ts possible to add a transparent transform stream to the |
I'm quoting #510 (comment) here, the quote reply didn't seem to work. For 1., I'm working on this, but for some extra protection I want to add a grace period after the timeout where the abort signal is sent before the stream is forced closed. This is to prevent the possibility of the handler failing to respect the abort signal. for 2, if the client cancels it's stream then the stream ends on the server side. I can send the abort signal at this point just as an extra measure. I don't think using symbols here is appropriate since the handler's perspective is external to the RPC. They should be descriptive errors. |
I've gone with two options, |
I believe we should separate these duties. The timer is best used for "keepalive". For preventing DOS, we should use a separate mechanism, one that tracks resource usage and starts killing things. That's more of an OOM. Not in-scope here. In fact, we can just leave that to the Operating System to deal with. |
No the problem is that In fact... I believe You are only given 2 options: So if you want to represent something as infinity, then I guess a very large number can be used. Something like |
I'm ok with not having an explicit infinite option. These are going to be valid values in the RPC JSON:
Note that if you provide a negative deadline, it should be clipped to However a Furthermore our deadline should be on the order of milliseconds. Not seconds. |
The A timeout value can be provided when implementing the handler. This value is used for the timeout if it is provided. If it is undefined or larger than |
What happens if Also |
Can you make sure to preserve the semantics of the words used? If you're using |
What did you end up doing for JSON? The |
Remember to update the spec above with the final design you arrived on. |
As for the JSON, I haven't started on that or fully specced it out. The underlying functionality of the If it's up to the middleware to communicate the timeouts then the message structure is out of scope for the agnostic RPC system. It's up to the middleware to define and implement this behaviour. As for what to set a timeout value in JSON if we want to use the default. |
I'll need to re-base this on #509. However I think Updating the client and agent handlers to use cancellation can be it's own issue/PR. Atomic tasks and all that. |
Can you provide some code examples of how these are used. |
about what specifically? |
About how timers are used, how to configure the middleware with respect to the timers. How timers can be propagated downstream contexts. Even execution with asciicast. |
If we debug what the JSON will look like. |
Ok, I can do that. |
Progress update:
|
First blush spec for communicating timeouts between client and server. Basically, the client and the server can communicate how long it will wait before timing out. Ideally the client and server can change their timeout behaviour based on this. There are a few parts to this.
There are some constraints to implementing this.
So to implement this feature, we need to provide the tools for a middleware to communicate the timeout values and update the timeouts. I don't see any other way without appending a timeout parameter to the To allow the middleware to update the timer, all we need to do is provide the |
Only problem with not putting the timeout into the params is that it is no longer compatible with JSONRPC. I think you should try to put it in the params and just not require strict typing. The timeout is an entirely optional property that you have to dynamically check no matter what because you cannot control who is sending requests. |
Generic error code for web sockets is now 4000. @tegefaulkes did you create the new issues for web socket error specification as well as any additional issues needed for future work involving the deadlines? |
I'll make then now. |
Specification
We need to support default and client supplied timeouts for the RPCServer handlers.
We need to support some features with this.
TimedCancellable
contextI need to do some prototyping with how I want to implement this. We have two options.
Note that the raw handlers don't support the middleware, It's pretty low level in that respect. So raw handlers wouldn't support timeouts with option 2. Conversely Option 1 means adding a timeout field to the RPC messages since by design the RPC system doesn't interpret or apply constraints to the params.
Given some constraints the first option would mean the timeout feature is always available and enforced. The second option means it's up to the implementation of the middleware and handlers to enforce it. I need to weigh both options after some prototyping. I'm leaning towards option 1, but It may require appending a field to the JSONRPC request message format.
RPCServer
changesRPCServer
when creating it. These aredefaultTimeout
andforceEndDelay
.defaultTimeout
sets the default amount of time before a handler times out and an abort signal is sent. Since this signal is advisory theforceEndDelay
(name subject to change) sets the time between the signal and the streamPair being directly aborted.defaultTimeout
. When a handler is selected the timer isreset
with the provided timeout for the handler if is is less than the default. If none is set then the timer is justrefresh
-ed.RPCServer
defaultTimeout
that was provided.signal
andtimer
are provided to the handlers as actx: ContextTimed
. The timer can berefresh
-ed orreset(delay)
or evencancel(reason)
. This gives us the freedom to override the timeout behaviour from the handlers if we want that. If that is not desired, we can reduce the functionality by casting it with a more restrictive interface.Additional context
timedCancellable
across the board to control how long side-effects are allowed to complete #450timedCancellable
toSigchain
such as the deadline in nodes claim process #243Tasks
RPCServer
handle timeouts and provide them to the handlersRPCClient
takes a timeout value or default and force closes the connection when exceeded.RPCClient
can communicate it's timeout to theRPCServer
.The text was updated successfully, but these errors were encountered: