issue: ENG-7821
When I tried using endpointValidators in callSingleKeyserverEndpoint it created import cycles which are hard to fix. An explenation can be found here.
The bottom line is that I cannot import lib/types/validators/endpoint-validators.js from lib/keyserver-conn/call-single-keyserver-endpoint.js. So my workaroud is for lib/keyserver-conn/call-single-keyserver-endpoint.js to expose a function that lets some other place in the code insert the handler to it.
Details
- Reviewers
tomek kamil ashoat - Commits
- rCOMM8a9622970949: [lib] Use httpMessageUserInfosHandler
Tested that both web and native apps can be run and no errors are thrown. Tested that the handler correctly extracts user ids from http messages.
Diff Detail
- Repository
- rCOMM Comm
- Lint
No Lint Coverage - Unit
No Test Coverage
Event Timeline
Is this really the only way to do it? I really don't like this solution, and it feels like something better must be possible.
I don't have time to look at your code directly, but I think it would be good if the reviewers here ran yarn arcpatch and tried to find an alternate solution.
@inka, can you please share the exact path of the import cycle that you are facing? Eg. file1 -> file2 -> file3 -> file1
In the past, when we've faced import cycle issues, we've worked directly to resolve them instead of hacking around them.
lib/keyserver-conn/call-single-keyserver-endpoint.js | ||
---|---|---|
81–86 ↗ | (On Diff #40286) | If this approach is absolutely necessary, we should be doing it in a separate file Part of the thing that contributes to import cycle issues is when we're doing too much in a single file |
web/root.js | ||
42 ↗ | (On Diff #40286) | Why do we need to register it separately on web and native? Can we import a shared file in lib that will just do the registration in a shared way? |
Is this really the only way to do it? I really don't like this solution, and it feels like something better must be possible.
I also dislike this solution, but I was unable to find anything I would consider better
@inka, can you please share the exact path of the import cycle that you are facing? Eg. file1 -> file2 -> file3 -> file1
The thing is that this is more than one import cycle. An example is:
lib/utils/reducers-utils.test.js fails with
cpp 38 | 39 | function tShape<T>(spec: TStructProps<T>): TInterface<T> { > 40 | return t.interface(spec, { strict: true }); | ^ 41 | } 42 | 43 | export type TRegex = TRefinement<string>; at Function.fail (../node_modules/tcomb/lib/fail.js:2:9) at assert (../node_modules/tcomb/lib/assert.js:14:12) at Function.inter (../node_modules/tcomb/lib/interface.js:38:5) at interface (utils/validation-utils.js:40:12) at Object.<anonymous> (shared/updates/join-thread-spec.js:172:24) at Object.require (shared/updates/update-specs.js:6:1) at Object.require (types/update-types.js:19:1) at Object.require (types/validators/entry-validators.js:20:1) at Object.require (types/validators/endpoint-validators.js:5:1) at Object.require (handlers/http-message-user-infos-handler.js:9:1) at Object.require (keyserver-conn/call-single-keyserver-endpoint.js:11:1) at Object.require (keyserver-conn/call-keyserver-endpoint-provider.react.js:12:1) at Object.require (keyserver-conn/keyserver-call.js:6:1) at Object.require (actions/thread-actions.js:7:1) at Object.require (shared/messages/text-message-spec.js:13:1) at Object.require (shared/messages/message-specs.js:21:1) at Object.require (shared/message-utils.js:11:1) at Object.require (selectors/thread-selectors.js:28:1) at Object.require (shared/avatar-utils.js:11:1) at Object.require (shared/thread-utils.js:10:1) at Object.require (permissions/special-roles.js:6:1) at Object.require (permissions/minimally-encoded-raw-thread-info-validators.js:9:1) at Object.require (types/request-types.js:30:1) at Object.require (types/socket-types.js:32:1)
because lib/shared/updates/join-thread-spec.js needs ThreadJoinUpdateInfo defined in lib/types/update-types.js , which is already on the stack. It is already on the stack, because it defines serverUpdateInfoValidator which requires updateSpecs which needs joinThreadSpec. serverUpdateInfoValidator cannot be easily moved out of the file, because it depends on many things in it, so it would have to import it anyway.
ThreadJoinUpdateInfo can be moved out of lib/types/update-types.js. But then the test still fails, because lib/shared/updates/update-thread-spec.js needs ThreadUpdateInfo defined in lib/types/update-types.js. If I fix that, the problem becomes that lib/shared/updates/update-thread-spec.js needs mixedRawThreadInfoValidator defined in lib/permissions/minimally-encoded-raw-thread-info-validators.js which is already on the stack. And so on.
because lib/shared/updates/join-thread-spec.js needs ThreadJoinUpdateInfo defined in lib/types/update-types.js , which is already on the stack
That doesn't sound right to me... I don't think Flow types contribute to import cycles. Are you sure that it's not some other non-type import from that file?
I checked this out locally to investigate a little bit on my flight. I ran yarn arcpatch D12073 from master, and then simplified this diff to be a direct import. Several tests started failing; I started my investigation with cd lib && yarn test permissions/minimally-encoded-thread-permissions.test.js.
I found the following pattern in the failure callstack:
at interface (utils/validation-utils.js:40:12) at Object.<anonymous> (shared/updates/join-thread-spec.js:172:24) at Object.require (shared/updates/update-specs.js:6:1) at Object.require (types/update-types.js:19:1) at Object.require (types/validators/entry-validators.js:20:1) at Object.require (types/validators/endpoint-validators.js:5:1) at Object.require (handlers/http-message-user-infos-handler.js:9:1) at Object.require (keyserver-conn/call-single-keyserver-endpoint.js:10:1) at Object.require (keyserver-conn/call-keyserver-endpoint-provider.react.js:12:1) at Object.require (keyserver-conn/keyserver-call.js:6:1) at Object.require (actions/thread-actions.js:7:1) at Object.require (shared/messages/text-message-spec.js:13:1) at Object.require (shared/messages/message-specs.js:21:1) at Object.require (shared/message-utils.js:11:1) at Object.require (selectors/thread-selectors.js:28:1) at Object.require (shared/avatar-utils.js:11:1) at Object.require (shared/thread-utils.js:10:1) at Object.require (permissions/special-roles.js:6:1) at Object.require (permissions/minimally-encoded-raw-thread-info-validators.js:9:1) at Object.require (permissions/minimally-encoded-thread-permissions.test.js:3:1)
I spent some time investigating different ways to address it by extracting functions to separate files. Ultimately I figured out a simple solution to the issue, which was to extract combineTruncationStatuses to a separate file. This stops the import cycle by breaking the relationship between the message and update specs.
In the process I extracted several other functions to separate files. I'll put diffs up for those too, since they are probably good things that may avoid import cycles in the future.
For the context, this investigation took me <1 hr. I think there are some strategies to handling import cycles that might not be non-obvious to @inka and others on the team; I'd suggest pairing with me in the future to help resolve these, and learn the skills necessary to resolve them on your own.