2

My clients can start a task from frontend (such as create PDF report), and the process pretty much like this: architecture of old system

In this architecture frontend need to create ajax call to check if PDF report is ready.

I want to update to web socket to make process more efficient.

  1. Should i use create another flask project or adding websocket support to old one? (adding another endpoint like api.my.domain/ws/create-report)
  2. How can i emit an event to client that job has been completed?

Ps: On a daily basis, each client generates 1000 tasks per day. On average, each task only takes 45 seconds to finish.

Angus G.
  • 79
  • 1
  • 6

2 Answers2

2

To be more efficient than polling, the server can send "Server Sent Events" and then the client can listen to those events. Server Sent Events can be easier to set up than websockets. Server Sent Events, like WebSockets, are both more efficient than polling. By listening to server sent events, the server only has to send one message to the client when it's done, instead of having to respond to many "is it done yet?" polling requests from many clients. This way, a client can be notified the moment their report is ready.

The flow would look something like this:

  • The client subscribes to the server's event stream at /listen
  • When the flask server finishes processing, it sends a message to the client
  • the client receives the message from the server that the file is ready.

The Client's code would look something like this to listen to events:

const evtSource = new EventSource("//api.example.com/listen", {
  withCredentials: true,
});

evtSource.onmessage = (event) => {
  //respond to the event here..
};

And the server would have an endpoint for clients to subscribe: (full code found in below article)

@app.route('/listen', methods=['GET'])
def listen():

    def stream():
        messages = announcer.listen()  # returns a queue.Queue
        while True:
            msg = messages.get()  # blocks until a new message arrives
            yield msg

    return flask.Response(stream(), mimetype='text/event-stream')

After listening for events, the client can then begin a request to get the PDF report ready, The flow would look something like this:

  • Client submits a request to start generating the PDF report.
  • The Flask server responds to the client with HTTP 202 (Accepted) before it's finished processing the PDF report, the flask server also begins waiting for the process to finish (you'd need to figure out how to record the client's information in an in-memory dictionary or database so that you can respond to the same client with the message later)
  • when the process is finished, it sends a message to the subscriber.

Read more about Server Sent Events Here: https://maxhalford.github.io/blog/flask-sse-no-deps/#:~:text=Server%2Dsent%20events%20(SSE),is%20all%20you%20might%20need.

Read more about client subscribing to events here: https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events

Nick Bonilla
  • 181
  • 6
0

I would use the simplest solution - the ajax request (polling).

You know an average delay (45 seconds, you can use something like 50 seconds delay or improve it look at probability function also you can use a smarter delays formula, for example, 50 sec, 20 sec, 20 sec...). It is a small additional load on your server. And you do not have to build more complicated architecture, which may not provide any significant benefits for users.

nik0x1
  • 152
  • 11