Skip to content

Commit 76e034c

Browse files
committedJun 15, 2015
protocols: add fire-and-forget RPC
1 parent a5b34be commit 76e034c

File tree

2 files changed

+58
-1
lines changed

2 files changed

+58
-1
lines changed
 

Diff for: ‎artiq/protocols/fire_and_forget.py

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import threading
2+
import logging
3+
4+
5+
logger = logging.getLogger(__name__)
6+
7+
8+
class FFProxy:
9+
"""Proxies a target object and runs its methods in the background.
10+
11+
All method calls to this object are forwarded to the target and executed
12+
in a background thread. Method calls return immediately. Exceptions from
13+
the target method are turned into warnings. At most one method from the
14+
target object may be executed in the background; if a new call is
15+
submitted while the previous one is still executing, a warning is printed
16+
and the new call is dropped.
17+
18+
This feature is typically used to wrap slow and non-critical RPCs in
19+
experiments.
20+
"""
21+
def __init__(self, target):
22+
self.target = target
23+
self._thread = None
24+
25+
def ff_join(self):
26+
"""Waits until any background method finishes its execution."""
27+
if self._thread is not None:
28+
self._thread.join()
29+
30+
def __getattr__(self, k):
31+
def run_in_thread(*args, **kwargs):
32+
if self._thread is not None and self._thread.is_alive():
33+
logger.warning("skipping fire-and-forget call to %r.%s as "
34+
"previous call did not complete",
35+
self.target, k)
36+
return
37+
def thread_body():
38+
try:
39+
getattr(self.target, k)(*args, **kwargs)
40+
except:
41+
logger.warning("fire-and-forget call to %r.%s raised an "
42+
"exception:", self.target, k, exc_info=True)
43+
self._thread = threading.Thread(target=thread_body)
44+
self._thread.start()
45+
return run_in_thread

Diff for: ‎artiq/test/pc_rpc.py

+13-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
import numpy as np
88

9-
from artiq.protocols import pc_rpc
9+
from artiq.protocols import pc_rpc, fire_and_forget
1010

1111

1212
test_address = "::1"
@@ -84,6 +84,18 @@ def test_asyncio_echo(self):
8484
self._run_server_and_test(self._loop_asyncio_echo)
8585

8686

87+
class FireAndForgetCase(unittest.TestCase):
88+
def _set_ok(self):
89+
self.ok = True
90+
91+
def test_fire_and_forget(self):
92+
self.ok = False
93+
p = fire_and_forget.FFProxy(self)
94+
p._set_ok()
95+
p.ff_join()
96+
self.assertTrue(self.ok)
97+
98+
8799
class Echo:
88100
def __init__(self):
89101
self.terminate_notify = asyncio.Semaphore(0)

0 commit comments

Comments
 (0)
Please sign in to comment.