mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-22 04:21:40 +08:00
fix(server): sse abort behavior (#13153)
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved handling of aborted client connections during streaming, ensuring that session messages accurately reflect if a request was aborted. * Enhanced consistency and reliability across all streaming endpoints when saving session messages after streaming. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -299,6 +299,13 @@ export class CopilotController implements BeforeApplicationShutdown {
|
|||||||
this.ongoingStreamCount$.next(this.ongoingStreamCount$.value + 1);
|
this.ongoingStreamCount$.next(this.ongoingStreamCount$.value + 1);
|
||||||
|
|
||||||
const { signal, onConnectionClosed } = getSignal(req);
|
const { signal, onConnectionClosed } = getSignal(req);
|
||||||
|
let endBeforePromiseResolve = false;
|
||||||
|
onConnectionClosed(isAborted => {
|
||||||
|
if (isAborted) {
|
||||||
|
endBeforePromiseResolve = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const { messageId, reasoning, webSearch } = ChatQuerySchema.parse(query);
|
const { messageId, reasoning, webSearch } = ChatQuerySchema.parse(query);
|
||||||
|
|
||||||
const source$ = from(
|
const source$ = from(
|
||||||
@@ -322,21 +329,21 @@ export class CopilotController implements BeforeApplicationShutdown {
|
|||||||
shared$.pipe(
|
shared$.pipe(
|
||||||
reduce((acc, chunk) => acc + chunk, ''),
|
reduce((acc, chunk) => acc + chunk, ''),
|
||||||
tap(buffer => {
|
tap(buffer => {
|
||||||
onConnectionClosed(isAborted => {
|
session.push({
|
||||||
session.push({
|
role: 'assistant',
|
||||||
role: 'assistant',
|
content: endBeforePromiseResolve
|
||||||
content: isAborted ? '> Request aborted' : buffer,
|
? '> Request aborted'
|
||||||
createdAt: new Date(),
|
: buffer,
|
||||||
});
|
createdAt: new Date(),
|
||||||
void session
|
|
||||||
.save()
|
|
||||||
.catch(err =>
|
|
||||||
this.logger.error(
|
|
||||||
'Failed to save session in sse stream',
|
|
||||||
err
|
|
||||||
)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
void session
|
||||||
|
.save()
|
||||||
|
.catch(err =>
|
||||||
|
this.logger.error(
|
||||||
|
'Failed to save session in sse stream',
|
||||||
|
err
|
||||||
|
)
|
||||||
|
);
|
||||||
}),
|
}),
|
||||||
ignoreElements()
|
ignoreElements()
|
||||||
)
|
)
|
||||||
@@ -384,6 +391,13 @@ export class CopilotController implements BeforeApplicationShutdown {
|
|||||||
this.ongoingStreamCount$.next(this.ongoingStreamCount$.value + 1);
|
this.ongoingStreamCount$.next(this.ongoingStreamCount$.value + 1);
|
||||||
|
|
||||||
const { signal, onConnectionClosed } = getSignal(req);
|
const { signal, onConnectionClosed } = getSignal(req);
|
||||||
|
let endBeforePromiseResolve = false;
|
||||||
|
onConnectionClosed(isAborted => {
|
||||||
|
if (isAborted) {
|
||||||
|
endBeforePromiseResolve = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const { messageId, reasoning, webSearch } = ChatQuerySchema.parse(query);
|
const { messageId, reasoning, webSearch } = ChatQuerySchema.parse(query);
|
||||||
|
|
||||||
const source$ = from(
|
const source$ = from(
|
||||||
@@ -407,25 +421,25 @@ export class CopilotController implements BeforeApplicationShutdown {
|
|||||||
shared$.pipe(
|
shared$.pipe(
|
||||||
reduce((acc, chunk) => acc.concat([chunk]), [] as StreamObject[]),
|
reduce((acc, chunk) => acc.concat([chunk]), [] as StreamObject[]),
|
||||||
tap(result => {
|
tap(result => {
|
||||||
onConnectionClosed(isAborted => {
|
const parser = new StreamObjectParser();
|
||||||
const parser = new StreamObjectParser();
|
const streamObjects = parser.mergeTextDelta(result);
|
||||||
const streamObjects = parser.mergeTextDelta(result);
|
const content = parser.mergeContent(streamObjects);
|
||||||
const content = parser.mergeContent(streamObjects);
|
session.push({
|
||||||
session.push({
|
role: 'assistant',
|
||||||
role: 'assistant',
|
content: endBeforePromiseResolve
|
||||||
content: isAborted ? '> Request aborted' : content,
|
? '> Request aborted'
|
||||||
streamObjects: isAborted ? null : streamObjects,
|
: content,
|
||||||
createdAt: new Date(),
|
streamObjects: endBeforePromiseResolve ? null : streamObjects,
|
||||||
});
|
createdAt: new Date(),
|
||||||
void session
|
|
||||||
.save()
|
|
||||||
.catch(err =>
|
|
||||||
this.logger.error(
|
|
||||||
'Failed to save session in sse stream',
|
|
||||||
err
|
|
||||||
)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
void session
|
||||||
|
.save()
|
||||||
|
.catch(err =>
|
||||||
|
this.logger.error(
|
||||||
|
'Failed to save session in sse stream',
|
||||||
|
err
|
||||||
|
)
|
||||||
|
);
|
||||||
}),
|
}),
|
||||||
ignoreElements()
|
ignoreElements()
|
||||||
)
|
)
|
||||||
@@ -477,6 +491,13 @@ export class CopilotController implements BeforeApplicationShutdown {
|
|||||||
this.ongoingStreamCount$.next(this.ongoingStreamCount$.value + 1);
|
this.ongoingStreamCount$.next(this.ongoingStreamCount$.value + 1);
|
||||||
|
|
||||||
const { signal, onConnectionClosed } = getSignal(req);
|
const { signal, onConnectionClosed } = getSignal(req);
|
||||||
|
let endBeforePromiseResolve = false;
|
||||||
|
onConnectionClosed(isAborted => {
|
||||||
|
if (isAborted) {
|
||||||
|
endBeforePromiseResolve = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const source$ = from(
|
const source$ = from(
|
||||||
this.workflow.runGraph(params, session.model, {
|
this.workflow.runGraph(params, session.model, {
|
||||||
...session.config.promptConfig,
|
...session.config.promptConfig,
|
||||||
@@ -526,21 +547,21 @@ export class CopilotController implements BeforeApplicationShutdown {
|
|||||||
return acc;
|
return acc;
|
||||||
}, ''),
|
}, ''),
|
||||||
tap(content => {
|
tap(content => {
|
||||||
onConnectionClosed(isAborted => {
|
session.push({
|
||||||
session.push({
|
role: 'assistant',
|
||||||
role: 'assistant',
|
content: endBeforePromiseResolve
|
||||||
content: isAborted ? '> Request aborted' : content,
|
? '> Request aborted'
|
||||||
createdAt: new Date(),
|
: content,
|
||||||
});
|
createdAt: new Date(),
|
||||||
void session
|
|
||||||
.save()
|
|
||||||
.catch(err =>
|
|
||||||
this.logger.error(
|
|
||||||
'Failed to save session in sse stream',
|
|
||||||
err
|
|
||||||
)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
void session
|
||||||
|
.save()
|
||||||
|
.catch(err =>
|
||||||
|
this.logger.error(
|
||||||
|
'Failed to save session in sse stream',
|
||||||
|
err
|
||||||
|
)
|
||||||
|
);
|
||||||
}),
|
}),
|
||||||
ignoreElements()
|
ignoreElements()
|
||||||
)
|
)
|
||||||
@@ -604,6 +625,13 @@ export class CopilotController implements BeforeApplicationShutdown {
|
|||||||
this.ongoingStreamCount$.next(this.ongoingStreamCount$.value + 1);
|
this.ongoingStreamCount$.next(this.ongoingStreamCount$.value + 1);
|
||||||
|
|
||||||
const { signal, onConnectionClosed } = getSignal(req);
|
const { signal, onConnectionClosed } = getSignal(req);
|
||||||
|
let endBeforePromiseResolve = false;
|
||||||
|
onConnectionClosed(isAborted => {
|
||||||
|
if (isAborted) {
|
||||||
|
endBeforePromiseResolve = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const source$ = from(
|
const source$ = from(
|
||||||
provider.streamImages(
|
provider.streamImages(
|
||||||
{
|
{
|
||||||
@@ -639,22 +667,20 @@ export class CopilotController implements BeforeApplicationShutdown {
|
|||||||
shared$.pipe(
|
shared$.pipe(
|
||||||
reduce((acc, chunk) => acc.concat([chunk]), [] as string[]),
|
reduce((acc, chunk) => acc.concat([chunk]), [] as string[]),
|
||||||
tap(attachments => {
|
tap(attachments => {
|
||||||
onConnectionClosed(isAborted => {
|
session.push({
|
||||||
session.push({
|
role: 'assistant',
|
||||||
role: 'assistant',
|
content: endBeforePromiseResolve ? '> Request aborted' : '',
|
||||||
content: isAborted ? '> Request aborted' : '',
|
attachments: endBeforePromiseResolve ? [] : attachments,
|
||||||
attachments: isAborted ? [] : attachments,
|
createdAt: new Date(),
|
||||||
createdAt: new Date(),
|
|
||||||
});
|
|
||||||
void session
|
|
||||||
.save()
|
|
||||||
.catch(err =>
|
|
||||||
this.logger.error(
|
|
||||||
'Failed to save session in sse stream',
|
|
||||||
err
|
|
||||||
)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
void session
|
||||||
|
.save()
|
||||||
|
.catch(err =>
|
||||||
|
this.logger.error(
|
||||||
|
'Failed to save session in sse stream',
|
||||||
|
err
|
||||||
|
)
|
||||||
|
);
|
||||||
}),
|
}),
|
||||||
ignoreElements()
|
ignoreElements()
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user