poll the backend for active users instead of keeping the connection open so it does not hang on a process w/ burnettk

This commit is contained in:
jasquat 2023-05-04 15:44:52 -04:00
parent c5d7a87e61
commit d6724087f6
3 changed files with 42 additions and 58 deletions

View File

@ -1,11 +1,10 @@
import json
import time
from typing import Generator
import flask.wrappers
from flask import current_app
from flask import g
from flask import stream_with_context
from flask import jsonify
from flask import make_response
from flask.wrappers import Response
from spiffworkflow_backend.models.active_user import ActiveUserModel
@ -24,20 +23,11 @@ def active_user_updates(last_visited_identifier: str) -> Response:
db.session.add(active_user)
db.session.commit()
return Response(
stream_with_context(_active_user_updates(last_visited_identifier, active_user=active_user)),
mimetype="text/event-stream",
headers={"X-Accel-Buffering": "no"},
)
def _active_user_updates(last_visited_identifier: str, active_user: ActiveUserModel) -> Generator[str, None, None]:
while True:
active_user.last_seen_in_seconds = round(time.time())
db.session.add(active_user)
db.session.commit()
cutoff_time_in_seconds = time.time() - 15
cutoff_time_in_seconds = time.time() - 30
active_users = (
UserModel.query.join(ActiveUserModel)
.filter(ActiveUserModel.last_visited_identifier == last_visited_identifier)
@ -45,9 +35,7 @@ def _active_user_updates(last_visited_identifier: str, active_user: ActiveUserMo
.filter(UserModel.id != g.user.id)
.all()
)
yield f"data: {current_app.json.dumps(active_users)} \n\n"
time.sleep(5)
return make_response(jsonify(active_users), 200)
def active_user_unregister(last_visited_identifier: str) -> flask.wrappers.Response:

View File

@ -247,15 +247,21 @@ export const splitProcessModelId = (processModelId: string) => {
export const refreshAtInterval = (
interval: number,
timeout: number,
func: Function
periodicFunction: Function,
cleanupFunction?: Function
) => {
const intervalRef = setInterval(() => func(), interval * 1000);
const timeoutRef = setTimeout(
() => clearInterval(intervalRef),
timeout * 1000
);
const intervalRef = setInterval(() => periodicFunction(), interval * 1000);
const timeoutRef = setTimeout(() => {
clearInterval(intervalRef);
if (cleanupFunction) {
cleanupFunction();
}
}, timeout * 1000);
return () => {
clearInterval(intervalRef);
if (cleanupFunction) {
cleanupFunction();
}
clearTimeout(timeoutRef);
};
};

View File

@ -25,9 +25,7 @@ import Col from 'react-bootstrap/Col';
import Editor, { DiffEditor } from '@monaco-editor/react';
import MDEditor from '@uiw/react-md-editor';
import { fetchEventSource } from '@microsoft/fetch-event-source';
import { BACKEND_BASE_URL } from '../config';
import HttpService, { getBasicHeaders } from '../services/HttpService';
import HttpService from '../services/HttpService';
import ReactDiagramEditor from '../components/ReactDiagramEditor';
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
import useAPIError from '../hooks/UseApiError';
@ -35,6 +33,8 @@ import {
makeid,
modifyProcessIdentifierForPathParam,
encodeBase64,
refreshAtInterval,
REFRESH_TIMEOUT_SECONDS,
} from '../helpers';
import {
CarbonComboBoxProcessSelection,
@ -134,6 +134,12 @@ export default function ProcessModelEditDiagram() {
const lastVisitedIdentifier = encodeBase64(window.location.pathname);
useEffect(() => {
const updateActiveUsers = () => {
HttpService.makeCallToBackend({
path: `/active-users/updates/${lastVisitedIdentifier}`,
successCallback: setActiveUsers,
});
};
// Grab all available process models in case we need to search for them.
// Taken from the Process Group List
const processResults = (result: any) => {
@ -155,30 +161,14 @@ export default function ProcessModelEditDiagram() {
successCallback: setActiveUsers,
});
};
fetchEventSource(
`${BACKEND_BASE_URL}/active-users/updates/${lastVisitedIdentifier}`,
{
headers: getBasicHeaders(),
onmessage(ev) {
const retValue = JSON.parse(ev.data);
if ('error_code' in retValue) {
addError(retValue);
} else {
setActiveUsers(retValue);
}
},
onclose() {
unregisterUser();
},
onerror(err: any) {
throw err;
},
}
);
updateActiveUsers();
// FIXME: this is not getting called when navigating away from this page.
// we do not know why yet.
return unregisterUser;
return refreshAtInterval(
15,
REFRESH_TIMEOUT_SECONDS,
updateActiveUsers,
unregisterUser
);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []); // it is critical to only run this once.