Skip to content

Commit

Permalink
fix/fallback_timeout_handling (#210)
Browse files Browse the repository at this point in the history
* fix/fallback_timeout_handling

by using a killable_event we can abort fallbacks that timedout avoiding multiple answers

closes OpenVoiceOS/ovos-core#389

also avoids sessions being able to kill each other's events, could be problematic in get_response and company

* fix tests

* fix tests
  • Loading branch information
JarbasAl authored Jun 18, 2024
1 parent 4125ced commit 2f986d6
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 6 deletions.
16 changes: 12 additions & 4 deletions ovos_workshop/decorators/killable.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import threading
from functools import wraps
from inspect import signature
from typing import Optional, Type

from ovos_bus_client.session import SessionManager
from ovos_utils import create_killable_daemon
from ovos_utils.fakebus import Message
import threading
from inspect import signature
from functools import wraps
from ovos_utils.log import LOG


class AbortEvent(StopIteration):
Expand Down Expand Up @@ -56,10 +58,16 @@ def create_killable(func):
def call_function(*args, **kwargs):
skill = args[0]
t = create_killable_daemon(func, args, kwargs, autostart=False)
sess = SessionManager.get()

def abort(_):
def abort(m: Message):
if not t.is_alive():
return
# check if session matches (dont kill events from other sessions)
sess2 = SessionManager.get(m)
if sess.session_id != sess2.session_id:
LOG.debug(f"ignoring '{msg}' kill event, event listener not created by this session")
return
if stop_tts:
skill.bus.emit(Message("mycroft.audio.speech.stop"))
if call_stop:
Expand Down
10 changes: 9 additions & 1 deletion ovos_workshop/skills/fallback.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@
from typing import Optional, List, Callable, Tuple

from ovos_bus_client import MessageBusClient
from ovos_bus_client.message import Message
from ovos_bus_client.message import Message, dig_for_message
from ovos_config import Configuration
from ovos_utils.events import get_handler_name
from ovos_utils.log import LOG
from ovos_utils.metrics import Stopwatch
from ovos_utils.skills import get_non_properties

from ovos_workshop.decorators.killable import killable_event
from ovos_workshop.decorators.compat import backwards_compat
from ovos_workshop.permissions import FallbackMode
from ovos_workshop.skills.ovos import OVOSSkill
Expand Down Expand Up @@ -356,6 +357,13 @@ def _handle_fallback_ack(self, message: Message):
"can_handle": self.can_answer(utts, lang)},
context={"skill_id": self.skill_id}))

def _on_timeout(self):
message = dig_for_message()
self.bus.emit(message.forward(
f"ovos.skills.fallback.{self.skill_id}.killed",
data={"error": "timed out"}))

@killable_event("ovos.skills.fallback.force_timeout", callback=_on_timeout)
def _handle_fallback_request(self, message: Message):
"""
Handle a fallback request, calling any registered handlers in priority
Expand Down
2 changes: 1 addition & 1 deletion test/unittests/skills/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ def _update_skill_settings():
stop_time = time()
stop_event.set()
thread.join()
self.assertAlmostEquals(self.skill.settings["test_val"], stop_time,
self.assertAlmostEqual(self.skill.settings["test_val"], stop_time,
0, f"run {i}")
self.assertNotEqual(self.skill.settings["test_val"],
self.skill._initial_settings["test_val"],
Expand Down
3 changes: 3 additions & 0 deletions test/unittests/skills/test_fallback_skill.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import time
from unittest import TestCase
from unittest.mock import patch, Mock

Expand Down Expand Up @@ -262,6 +263,8 @@ def mock_resonse(message: Message):
self.fallback_skill._fallback_handlers = [(100, mock_handler)]

self.fallback_skill._handle_fallback_request(Message("test"))
time.sleep(0.2) # above runs in a killable thread

self.assertTrue(start_event.is_set())
self.assertTrue(handler_event.is_set())

Expand Down

0 comments on commit 2f986d6

Please sign in to comment.