From f3b5bf6b3f0a3f46296128f731dac0bd8e7a2c23 Mon Sep 17 00:00:00 2001 From: Antoine Prieels Date: Thu, 5 Nov 2020 14:00:41 +0000 Subject: [PATCH] [FIX] hw_drivers: Lost IoT events Events coming from the IoT Box were lost in two cases: 1. Create a listener for device 1 2. Send an action to device 1 --> If the action arrives before the listener the event is never sent to the DB 1. Setup up two listeners for devices 1 & 2 2. After a few seconds, send two consecutive actions to devices 1 & 2 --> Everytime a longpolling request arrives, a new threading.Event object is created. The first action sets the event, then, before the new longpolling request arrives, the second action sets the same event, which is overwritten once the new longpolling request arrives. We now maintain a list of events, and when a longpolling request arrives on the IoT Box, we make sure that all events that occured in the last 5 seconds were received by the DB. If no events were pending, we wait 50 seconds to check if a new one pops up. Taskid: 2320958 X-original-commit: e3260712ce96a8d81bf807574c334d92c37c6ae4 --- addons/hw_drivers/controllers/driver.py | 13 +++++++++++++ addons/hw_drivers/event_manager.py | 12 +++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/addons/hw_drivers/controllers/driver.py b/addons/hw_drivers/controllers/driver.py index 39ac2408947..ba2f2965f0d 100755 --- a/addons/hw_drivers/controllers/driver.py +++ b/addons/hw_drivers/controllers/driver.py @@ -6,6 +6,7 @@ import json import logging import os import subprocess +import time from odoo import http, tools from odoo.http import send_file @@ -48,6 +49,18 @@ class DriverController(http.Controller): listener is a dict in witch there are a sessions_id and a dict of device_identifier to listen """ req = event_manager.add_request(listener) + + # Search for previous events and remove events older than 5 seconds + oldest_time = time.time() - 5 + for event in list(event_manager.events): + if event['time'] < oldest_time: + del event_manager.events[0] + continue + if event['device_identifier'] in listener['devices'] and event['time'] > listener['last_event']: + event['session_id'] = req['session_id'] + return event + + # Wait for new event if req['event'].wait(50): req['event'].clear() req['result']['session_id'] = req['session_id'] diff --git a/addons/hw_drivers/event_manager.py b/addons/hw_drivers/event_manager.py index 59d30ea2318..c55c0d9c79a 100644 --- a/addons/hw_drivers/event_manager.py +++ b/addons/hw_drivers/event_manager.py @@ -7,6 +7,7 @@ import time class EventManager(object): def __init__(self): + self.events = [] self.sessions = {} def _delete_expired_sessions(self, max_time=70): @@ -37,10 +38,15 @@ class EventManager(object): return self.sessions[listener['session_id']] def device_changed(self, device): + event = { + **device.data, + 'device_identifier': device.device_identifier, + 'time': time.time(), + } + self.events.append(event) for session in self.sessions: - if device.device_identifier in self.sessions[session]['devices']: - self.sessions[session]['result'] = device.data - self.sessions[session]['result']['device_identifier'] = device.device_identifier + if device.device_identifier in self.sessions[session]['devices'] and not self.sessions[session]['event'].isSet(): + self.sessions[session]['result'] = event self.sessions[session]['event'].set()