Skip to content
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

feat: incorporate timeoutMiddleware to allow for server to utilise client's caller timeout #42

Merged
merged 3 commits into from
Oct 30, 2023

Conversation

addievo
Copy link
Contributor

@addievo addievo commented Oct 12, 2023

Description

Timeout Middleware

This PR moves timeoutMiddleware from Polykey to js-rpc. The middleware allows for the RPCServer to lessen it's timeout based on the advisory timeout set by the client. This has been decided to be moved across to js-rpc, as realistically it should be a core feature.

The metadata type will have to be moved across as well, but with the authentication property removed, as that's not in the scope of the timeoutMiddleware.

// Prevent overwriting the metadata type with `Omit<>`
type JSONRPCRequestMetadata<T extends Record<string, JSONValue> = ObjectEmpty> =
  {
    metadata?: {
      [Key: string]: JSONValue;
    } & Partial<{
      timeout: number | null;
    }>;
  } & Omit<T, 'metadata'>;

// Prevent overwriting the metadata type with `Omit<>`
type JSONRPCResponseMetadata<
  T extends Record<string, JSONValue> = ObjectEmpty,
> = {
  metadata?: {
    [Key: string]: JSONValue;
  } & Partial<{
    timeout: number | null;
  }>;
} & Omit<T, 'metadata'>;

Optional Timeout Throwing for Handlers

It was found that timing out would automatically throw an error from js-timer. This was because it was not checked whether the Timer instances had been settled or not before timer.reset() and timer.refresh() had been called. This has now been fixed, meaning that ErrorRPCTimedOut is now propagated to ctx.signal, and can be optionally thrown by the handler as intended.

Issues Fixed

Tasks

  • 1. Move relevant types from PK
  • 2. Import timeoutMiddlewareClient and timeoutMiddlewareServer from PK src/client/timeoutMiddleware.
  • 3. Implement timeoutMiddleware in defaultMiddleware.
  • 4. Provide spec on the timeout behavior on the README.md - so it can be consistent
  • 5. On the server handlers, if the timeout has occurred, the handlers need to be able to ignore it, and continue executing, there shouldn't be a timeout error - the client call may have already thrown
  • 6. The serialisation of Infinity is null, therefore timeout has to be null | number on the JSON RPC message type metadata.

Final checklist

  • Domain specific tests
  • Full tests
  • Updated inline-comment documentation
  • Lint fixed
  • Squash and rebased
  • Sanity check the final build

@addievo addievo linked an issue Oct 12, 2023 that may be closed by this pull request
@addievo addievo self-assigned this Oct 12, 2023
@ghost
Copy link

ghost commented Oct 12, 2023

👇 Click on the image for a new way to code review

Review these changes using an interactive CodeSee Map

Legend

CodeSee Map legend

src/types.ts Outdated Show resolved Hide resolved
@CMCDragonkai
Copy link
Member

This PR name is too specific, make sure to consider all of the issue scope.

@addievo addievo force-pushed the feature-middlware-composition branch from 8a974ad to 6ac87c6 Compare October 12, 2023 07:48
@addievo
Copy link
Contributor Author

addievo commented Oct 12, 2023

Ready for review

@CMCDragonkai
Copy link
Member

Rebase on staging.

And it's ready for review... not ready for merge.

@addievo addievo changed the title feat: Implement timeoutMiddleware to js-rpc feat: implement JSONRPCResponseResult and JSONRPCResponseError types, replicate timeoutMiddleware from Polykey and implement it in defaultMiddleware ensuring optimal functionality Oct 12, 2023
@addievo
Copy link
Contributor Author

addievo commented Oct 12, 2023

Rebased on staging

@CMCDragonkai
Copy link
Member

Open up a co-PR on PK that assumes this is being integrated. I need to see the whole context.

@tegefaulkes
Copy link
Contributor

@CMCDragonkai I need more context about the spec before I can do a full review.

I recall discussing that we'd move the metadata out of the params and response fields and merge it into the JSONRPC message structure as optional parameters. Is that still a requirement?

For example, the JSONRPCRequestMessage becomes something like this?

// old
type JSONRPCRequestMessage<T extends JSONValue = JSONValue> = {
  jsonrpc: '2.0';
  method: string;
  params?: T;
  id: string | number | null;
};

// new
type JSONRPCRequestMessage<T extends JSONValue = JSONValue> = {
  jsonrpc: '2.0';
  method: string;
  params?: T;
  id: string | number | null;
  metadata?: {
    timeout?: number | null;
  } & Omit<Record<string, JSONValue>, 'timeout'>;
};

@CMCDragonkai
Copy link
Member

@CMCDragonkai I need more context about the spec before I can do a full review.

I recall discussing that we'd move the metadata out of the params and response fields and merge it into the JSONRPC message structure as optional parameters. Is that still a requirement?

For example, the JSONRPCRequestMessage becomes something like this?

// old
type JSONRPCRequestMessage<T extends JSONValue = JSONValue> = {
  jsonrpc: '2.0';
  method: string;
  params?: T;
  id: string | number | null;
};

// new
type JSONRPCRequestMessage<T extends JSONValue = JSONValue> = {
  jsonrpc: '2.0';
  method: string;
  params?: T;
  id: string | number | null;
  metadata?: {
    timeout?: number | null;
  } & Omit<Record<string, JSONValue>, 'timeout'>;
};

What's the trade off here? Is it just that we leave the json RPC spec? Maybe it's necessary.

@tegefaulkes
Copy link
Contributor

I think it's needed. It's a hard requirement that we can't impose structure on the params and response of the messages. These are purely application defined. So if we have default timeout middleware that requires a timeout parameter in the message, it can't be part of the application supplied data.

But this has other consequences, if metadata is no longer supplied as part of the input and output of the caller and handler, then how does the caller and handler access or set the metadata now?

If we DO impose structure on the params and result then they can't be JSONValue anymore. It needs to be a Record<string, JSONValue> and we need to enforce types on the metadata and required parameters while preventing the application from overwriting their types. That may be easier to implement since there will be less changes to the API. But if we're using the RPC from the 3rd party perspective, the structure of the params will need to be know and that has usability issues since we're still diverging from the JSONRPC spec.

In either case there is more work to be done here.

@tegefaulkes
Copy link
Contributor

tegefaulkes commented Oct 27, 2023

Based on discussion, we're going to expand on the params and result parameter types to include the metadata and timeout. This has the least required changes to make this work.

we need to modify the JSONRPC message types to reflect this.

I'd have to fully review the changes to know what's still needed. But the following needs to change.

  1. JSONRPC messages are updated so the at the RPCRequestParams<T> is used for the params type, and the RPCResponseResult<T> is used for the result type. The T is now T extends Record<string, JSONValue> = ObjectEmpty.
  2. Tests need to be updated to reflect this.
  3. Need to check that any arbitrary metadata can be provided, but the timeout type can't be overwritten.

@CMCDragonkai
Copy link
Member

This will come after #47, and @amydevs can take over this to update the JSON RPC types, and factor out the timeout middleware.

@amydevs amydevs changed the title feat: implement JSONRPCResponseResult and JSONRPCResponseError types, replicate timeoutMiddleware from Polykey and implement it in defaultMiddleware ensuring optimal functionality feat: incorporate timeoutMiddleware to allow for server to utilise client's caller timeout Oct 27, 2023
…eatures

- Import ClientRPCResponseResult and ClientRPCRequestParams from PK.
- Implement timeoutMiddlewareServer and timeoutMiddlewareClient.
- Integrate timeoutMiddleware into defaultMiddleware.
- Fix Jest test issues.
- Rename to RPCResponseResult and RPCRequestParams for clarity.
- Perform lint fixes and Jest tests.

fix: timeouts are now only propagated unidirectionally from the client to the server

[ci-skip]
@amydevs amydevs force-pushed the feature-middlware-composition branch from 826823b to 228f824 Compare October 27, 2023 05:15
@amydevs
Copy link
Member

amydevs commented Oct 27, 2023

Should be ready to review, still need to update description, cos i pushed a few unrelated fixes regarding another issue

src/types.ts Outdated Show resolved Hide resolved
src/middleware.ts Outdated Show resolved Hide resolved
@CMCDragonkai
Copy link
Member

@amydevs tasks on OP spec need to be covered.

@CMCDragonkai
Copy link
Member

@amydevs can you also explain what also needs to be done on PK as well to support this change? What will need to be removed. Is there an existing issue in MatrixAI/Polykey-CLI#40?

…meouts

fix: changes to `ObjectEmpty` type to be in line with polykey

[ci-skip]
@amydevs amydevs force-pushed the feature-middlware-composition branch from 92e5919 to caa9bda Compare October 30, 2023 01:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

Factoring out the Timeout Middleware from PK to js-rpc
4 participants