-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
Stop using aborted
event for KibanaRequest.events.aborted$
#126184
Merged
pgayvallet
merged 7 commits into
elastic:main
from
pgayvallet:kbn-125240-aborted-event-node-16
Feb 23, 2022
Merged
Changes from 2 commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
f97fc7d
Stop using `aborted` event for `KibanaRequest.events.aborted$`
pgayvallet 302f5aa
add another test, just in case
pgayvallet 19b120b
use a single `fromEvent`
pgayvallet df3173b
add replay effect to aborted$
pgayvallet 8859e93
improve impl
pgayvallet f9129eb
remove useless bottom-stream replay
pgayvallet be0a2f6
yup, that's simpler
pgayvallet File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,7 +10,7 @@ import { URL } from 'url'; | |
import uuid from 'uuid'; | ||
import { Request, RouteOptionsApp, RequestApplicationState, RouteOptions } from '@hapi/hapi'; | ||
import { Observable, fromEvent, merge } from 'rxjs'; | ||
import { shareReplay, first, takeUntil } from 'rxjs/operators'; | ||
import { shareReplay, first, takeUntil, filter } from 'rxjs/operators'; | ||
import { RecursiveReadonly } from '@kbn/utility-types'; | ||
import { deepFreeze } from '@kbn/std'; | ||
|
||
|
@@ -127,6 +127,7 @@ export class KibanaRequest< | |
const body = routeValidator.getBody(req.payload, 'request body'); | ||
return { query, params, body }; | ||
} | ||
|
||
/** | ||
* A identifier to identify this request. | ||
* | ||
|
@@ -215,11 +216,24 @@ export class KibanaRequest< | |
} | ||
|
||
private getEvents(request: Request): KibanaRequestEvents { | ||
// the response is completed, or its underlying connection was terminated prematurely | ||
const finish$ = fromEvent(request.raw.res, 'close').pipe(shareReplay(1), first()); | ||
// the response is completed | ||
const finished$ = fromEvent<void>(request.raw.res, 'close').pipe( | ||
filter(() => { | ||
return isCompleted(request); | ||
}), | ||
first() | ||
); | ||
|
||
// the response's underlying connection was terminated prematurely | ||
const aborted$ = fromEvent<void>(request.raw.res, 'close').pipe( | ||
filter(() => { | ||
return !isCompleted(request); | ||
}), | ||
first(), | ||
takeUntil(finished$) | ||
); | ||
|
||
const aborted$ = fromEvent<void>(request.raw.req, 'aborted').pipe(first(), takeUntil(finish$)); | ||
const completed$ = merge<void, void>(finish$, aborted$).pipe(shareReplay(1), first()); | ||
const completed$ = merge<void, void>(finished$, aborted$).pipe(shareReplay(1), first()); | ||
|
||
return { | ||
aborted$, | ||
|
@@ -331,3 +345,7 @@ function isRequest(request: any): request is Request { | |
export function isRealRequest(request: unknown): request is KibanaRequest | Request { | ||
return isKibanaRequest(request) || isRequest(request); | ||
} | ||
|
||
function isCompleted(request: Request) { | ||
return request.raw.res.writableFinished; | ||
} | ||
Comment on lines
+334
to
+336
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I initially tried to use only one source
fromEvent
observable, two destination subjects, and manually emitting to these depending onisCompleted
, but the implementation was, in the end, more complex, and more vulnerable to edge cases such as errors. Given we were already usingfromEvent
twice before these changes, I think it's acceptable anyway.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RxJS noob question here: do we still get any benefit from having one
fromEvent
observable?I'm not sure about the internal implementation of RxJS, but it looks like it'd create only one listener to the
close
event? Question is... would it work as expected?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From the fromEvent documentation:
To answer @afharo 's question, I created a small StackBlitz to confirm that 2 listeners are created / attached anyway with the proposed approach.
If you really want to have a single listener to the original event, there is no need to create Subjects and emit to them. I believe you can simply use the share operator:
const closed$ = fromEvent<void>(request.raw.res, 'close').pipe(share());
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder whether the
finished$
andaborted$
Observables should also have the replay behavior.Your proposed
finished$
does not have it anymore (as opposed tofinish$
), which means if somebody subscribes to the event after it has happened they will just miss it and might get stuck.IMHO there's no harm in replaying the last event (if it exists) for this type of network related events (we do have a
first()
, which ensures we'll only be getting one).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's true, but
finished$
is only internal and the publiccompleted$
observable subscribes to it 'instantly' (no return to the ev loop, so no risk for the event to fire in the middle), and has a replay effect, so I think it was unnecessary to have it in two places.Regarding
aborted$
, there was no replay effect before the PR, and adding one did break tests, so I felt it was safer to KISS and preserve the original behavior as much as possible.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, perhaps we can reorder the operators and use
first()
first, this way there is no need to usetakeUntil()
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nevermind regarding adding replay to aborted$, it was probably very late yesterday. changes in 19b120b and df3173b
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Definitely better, yea. PR updated.