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

Improve RPC message encoding #11294

Merged
merged 2 commits into from
Jun 21, 2022
Merged

Conversation

tortmayr
Copy link
Contributor

What it does

  • Refactor RPCMessageEncoder to enable detection of circular object structures. Circular structures can not be serialized. The detection enables us to fail early instead of indirectly failing once the maximum stack frame limit is reached.
  • Add a custom encoder for functions. This ensures that direct function entries in arrays can be serialized.
  • Add custom encoder for common collection types (maps, sets). Enables direct use of collection types as rpc call arguments (e.g. logging statements)
  • Restore behavior of the old protocol if a log RPC call can not be sent to the backend due to an encoding error
    • Add custom EncodingError type to explicitly catch these errors
    • Refactor loggerFrontendModule to catch encoding errors and continue execution normally. i.e. log call is just logged in frontend console and not sent to backend

Fixes #11249

Contributed on behalf of STMicroelectronics

How to test

The bug described in #11249 (comment) should be fixed. i.e.:

  1. Add this log to DebugSessionManager set currentSession:
console.log('SENTINEL FOR SETTING THE CURRENT SESSION', current);
  1. Start a debug session inside the application.
  2. Observe that the frontend (browser) logs log the message as expected.
  3. Observe that no error logged in the frontend console
  4. Observe that the backend logs do not show the message
    ( Same behavior as with the old RPC protocol)

Review checklist

Reminder for reviewers

- Refactor `RPCMessageEncoder` to enable detection of circular object structures. Circular structures can not be serialized. The detection enables us to fail early instead of indirectly failing once the maximum stack frame limit is reached.
- Add a custom encoder for functions. This ensures that direct function entries in arrays can be serialized.
- Add custom encoder for common collection types (maps, sets). Enables direct use of collection types as rpc call arguments (e.g. logging statements)
- Restore behavior of the old protocol if a log RPC call can not be sent to the backend due to an encoding error 
   - Add custom `EncodingError` type to explicitly catch these errors
   - Refactor `loggerFrontendModule` to catch encoding errors and continue execution normally. i.e. log call is just logged in frontend console and not sent to backend

Fixes eclipse-theia#11249

Contributed on behalf of STMicroelectronics
Copy link
Contributor

@colin-grant-work colin-grant-work left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've only glanced over the code, but functionally this appears to be in order. Circular objects (tested on all Widgets that pass through the WidgetManager) are logged to the front end console without error and nothing appears in the backend log output. Logging many logs also appears much snappier than before the change.

Copy link
Contributor

@tsmaeder tsmaeder left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think circular structures can still slip through, see comments.

@@ -388,6 +428,16 @@ export class RpcMessageEncoder {
write: (buf, value) => buf.writeString(JSON.stringify(value))
});

this.registerEncoder(ObjectType.Map, {
is: value => value instanceof Map,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we have to treat anything that can hold a reference the same as the typeof x === object? I mean I can do

const x= new Set();
const y= new Set();
x.add(y);
y.add(x);

Bingo, circular reference 🤷

Copy link
Contributor

@colin-grant-work colin-grant-work Jun 16, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sets aren't a problem here, but JavaScript is, since if you want to, you can treat almost anything as an object:

const a = new Set();
// undefined
typeof a
// 'object'
const b = 'hello'
// undefined
const c = 'other string'
// undefined
 b.c = c;
// 'other string'
 c.b = b
// 'hello'
typeof b
// 'string'

TypeScript wouldn't allow exactly that syntax, but it would be happy with this:

const d = 'yet another string'
// undefined
const e = 'a fourth string'
// undefined
Object.assign(d, {e});
// [String: 'yet another string'] { e: 'a fourth string' }
typeof d
// 'string'

But as long as we have know where the border is between things whose fields we'll visit (all object types other than null?) and those whose fields we won't (primitives, functions), and we use the reference checker for the former, it should be safe - i.e. we need to make sure that all handlers of object types are delegates of the object handler.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. I have refactored the code and now all object types (other than null/undefined) are going through the reference check. I have also added a test case for circular references based on the example that @tsmaeder provided.

- Remove default value for `visitedObjects` parameter
- Move circular reference check from the `object` value encoder  into `wirteTypeValue` to ensure that all the ciruclar reference check is applied on all object references
@tortmayr
Copy link
Contributor Author

Thanks for the review @tsmaeder & @colin-grant-work. I have pushed an update that should address the review comments.

@JonasHelming JonasHelming requested a review from tsmaeder June 20, 2022 11:07
@tsmaeder
Copy link
Contributor

The code looks correct to me now and cursory testing revealed no obvious problems.

@JonasHelming JonasHelming merged commit 9da47d0 into eclipse-theia:master Jun 21, 2022
@JonasHelming JonasHelming added this to the 1.27.0 milestone Jun 21, 2022
@vince-fugnitto vince-fugnitto added the messaging issues related to messaging label Jun 30, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
messaging issues related to messaging
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Application freeze at startup with many errors in RPC system
5 participants