0
votes

I'm using flask_socketio.

@socketio.on('client_connected')
def handle_client_connect_event(data):
    if current_user.is_authenticated:
        thread = socketio.start_background_task(background_thread, user_id=current_user.id)
        logger.info('server socket client_connected, user:{}', current_user.id)
        emit('server_response', {'data': {'job_id': 'job1', 'name': 'hello'}})
    else:
        logger.info('server socket client_connected, user not authenticated.....')
def background_thread(user_id):
    pubsub = redisc.pubsub()
    redis_suscriber = redis_channel+str(user_id)
    pubsub.psubscribe(redis_suscriber)
    logger.info("new thread for: "+redis_suscriber)
    for item in pubsub.listen():
        logger.info('message received:{}', item)
        data_item = item['data']
        if isinstance(data_item, bytes):
            try:
                data_item = json.loads(data_item)
                job_id = data_item['job_id']
                log_data = data_item['log']
                data = {'data': {'job_id': job_id, 'user_id': user_id,
                                 'log': security_util.base64_decrypt(log_data).decode("utf-8")}}
                socketio.emit('server_response', data)
            except ValueError as e:
                logger.error("Error decoding msg to microservice: {}", str(e))
@socketio.on('disconnect')
def disconnected():
    if current_user.is_authenticated:
        logger.info('user:{} disconnected', current_user.id)
    else:
        logger.info('client disconnected, user not authenticated.....')

There are js code to establish websocket connection from web browser page to flask server.

When the web browser page is closed, "for item in pubsub.listen():" is still functioning.

So when I open the page and close the page for 3 times, flask server will subscribe the same redis topic for 3 times, and emit the same websocket message for 3 times.

Is there a way to terminate "def background_thread(user_id)" after the web browser page is closed(js client disconnected from websocket server)?

1
You have to code your thread in a way that you can interrupt it. For example, when you get the disconnect event for your client, send some special message to the thread via redis to let it know that it needs to exit. - Miguel
@Miguel Thanks for your reply! Would your please provide me with some example code? - Bruce Han
I don't have any example that is similar to your case to show you. Isn't the description I gave you above sufficient? - Miguel
@Miguel Thanks for your reply! In order to explain the difficulty I met, I posted an answer below. Will you please give me some tips. Thanks very much! - Bruce Han
The start_background_task() function returns a task identifier, so you do know which task belongs to each client. You have to keep that state somewhere, so that you can then recover the task that belongs to a client and signal it to end. - Miguel

1 Answers

0
votes

@Miguel Thanks for your reply!

I will try to explain the difficulty I met. Please forgive me, my English is not very good.

If I open two web pages, there will be two websocket clients: wsclient1 and wsclient2。 And there will be two redis subscribers: rsub1 and rsub2, in two threads.

for item in pubsub.listen():
    if ${condition}:
       break

If weclient1 disconnect from websocket server, then disconnected() method will be invoked.

  1. How do I define the ${condition}? 'disconnected()'' method and 'redis subscriber' belong to two different threads.
  2. How do I know which one should be terminated? I don'k know which 'redis subscriber' should mapped to wsclient1.