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:
parent
c5d7a87e61
commit
d6724087f6
|
@ -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,30 +23,19 @@ 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"},
|
||||
active_user.last_seen_in_seconds = round(time.time())
|
||||
db.session.add(active_user)
|
||||
db.session.commit()
|
||||
|
||||
cutoff_time_in_seconds = time.time() - 30
|
||||
active_users = (
|
||||
UserModel.query.join(ActiveUserModel)
|
||||
.filter(ActiveUserModel.last_visited_identifier == last_visited_identifier)
|
||||
.filter(ActiveUserModel.last_seen_in_seconds > cutoff_time_in_seconds)
|
||||
.filter(UserModel.id != g.user.id)
|
||||
.all()
|
||||
)
|
||||
|
||||
|
||||
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
|
||||
active_users = (
|
||||
UserModel.query.join(ActiveUserModel)
|
||||
.filter(ActiveUserModel.last_visited_identifier == last_visited_identifier)
|
||||
.filter(ActiveUserModel.last_seen_in_seconds > cutoff_time_in_seconds)
|
||||
.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:
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
Loading…
Reference in New Issue