Nexus Writer architecture
Nexus writer architecture
- Redis Subscriber
- Subscriber
- NexusScanWriter
- NexusSessionWriter
- Synchronization primitives
- HubTrigger
- Lock/Rlock
- ThreadResource
- Event
- Queue
- Thread
- Launcher
- AsyncResult
Redis subscriber
class Subscriber
Process events of one Redis node
Uses bliss.data.node classes for listening (gevent architecture)
Event listener and consumer can run in different modes:
- Sequential: listening and consuming happens sequentially in 1 greenlet
- Concurrent: 1 listener greenlet and 1 consumer greenlet (+ queue)
- Parallel (when GIL released in consumer): 2 threads (one for the listener greenlet and one for the consumer greenlet) or 1 thread (listener greenlet runs in the start thread)
Redis subscriber
class Subscriber
API
node: Redis node (thread/greenlet safe)
info: Redis node info
state: INIT, ON, OFF, FAULT
start(wait=False, timeout=None): INIT -> ON
stop(wait=False, timeout=None): ON -> OFF
kill(wait=False, timeout=None): ON -> FAULT
join(timeout=None): wait until finished (OFF or FAULT)
done(): finished?
duration(): listening time
Redis subscriber
class Subscriber
Synchronization primitives
Launcher: to execute functions in the start thread
gevent.Queue (concurrent): queue in listener and dequeue in consumer (same thread)
Queue (parallel): queue in listener and dequeue in consumer (different threads)
Thread (parallel): to execute functions in the listener and consumer thread
Redis subscriber
class NexusScanWriter(Subscriber)
Process events of one Scan node
Consumer saves Scan data in Nexus compliant HDF5 format
When running in parallel mode, HDF5 writing (consumer) and Redis event reception (listener) run in parallel (h5py releases the GIL on IO).
Redis subscriber
class NexusSessionWriter(Subscriber)
Process events of one Session node
Runs in sequential mode (1 greenlet in the start thread)
Consumer starts a NexusScanWriter in parallel mode for every new scan. It uses one Thread for the consumer greenlets of all scans. The listener greenlets run in the start thread.
A NexusWriter Tango device manages one NexusSessionWriter which is started in the MainThread (server runs in green mode).
NexusWriterService servername --log=info --logfile=...
Synchronization primitives
Primitives that can be shared across threads and greenlets:
Lock, RLock, Event and Queue
Execute function in another thread:
HubTrigger (without arguments and result)
Launcher (with arguments and result)
Synchronization primitives
class HubTrigger
Trigger function executing in a Hub from any thread.
No arguments passing or receiving result/exception.
API
__init__(func, blocking=False)
send(): causes func to be executed in the hub of the instantiating thread (spawns a greenlet for execution when blocking==False)
Synchronization primitives
threading.Lock: protect against coalescence of triggers
Synchronization primitives
class Lock
Can be acquired once by only one greenlet (across threads)
API
acquire(blocking=True, timeout=None)
release()
Synchronization primitives
threading.Lock:
Remark: "loop + gevent.sleep" when acquiring (only location where I have to do this)
Synchronization primitives
class RLock
Can be acquired multiple times by only one greenlet (across threads)
API
acquire(blocking=True, timeout=None)
release()
Synchronization primitives
threading.RLock:
ThreadResource(gevent.lock.RLock): one gevent RLock per thread
Synchronization primitives
class ThreadResource
Resource that dies with the thread and can be accessed in other threads
API
__init__(init_resource): function to generate the resource
get(): retrieve or create/cache resource for the current thread
pop(): remove the resource for the current thread (if cached)
__iter__(): loop over all thread resources
Synchronization primitives
WeakKeyDictionary: weakref(thread) -> resource
Lock: protect WeakKeyDictionary
Synchronization primitives
class Event
Shared across threads and greenlets
API
wait(timeout=None)
send()
clear()
Synchronization primitives
Lock: protect send and clear (as multiple events are involved)
ThreadResource((gevent.event.Event, HubTrigger(ev.set)))
Synchronization primitives
class Queue
Shared across threads and greenlets
API
put(item)
get()
Synchronization primitives
Lock: protect the queue+event
Event: notify the getters of a new item
Synchronization primitives
class Thread
Has methods to execute functions in this thread from any thread.
Has a stop mechanism.
Result or exception from the thread's main function can be retrieved.
Synchronization primitives
class Thread
API
start(wait=True, timeout=None)
stop(wait=True, timeout=None)
join(timeout=None):
get(timeout=None): like join but return value or raise exception
spawn(run=func, *args, **kwargs)
apply(func, *args, **kwargs)
apply_async(func, *args, **kwargs): returns AsyncResult
Synchronization primitives
class Thread
Synchronization primitives
Launcher: to queue execution in this thread
Event: for start and stop
Synchronization primitives
class Launcher
Execute a function in the instantiating thread from any thread.
Pass arguments and retrieve return value or raise exception.
API
apply(func, *args, **kwargs)
apply_async(func, *args, **kwargs): returns AsyncResult
Synchronization primitives
Queue: tasks enqueued by apply or apply_sync
HubTrigger: dequeue and execution in the instantiating thread
AsyncResult: result of apply_async
Synchronization primitives
class AsyncResult
Shared across threads and greenlets
API
set(result): can be an exception
get(timeout=None): raise when result is an exception
wait(timeout=None):
ready():
successful():
Synchronization primitives
Event: notify getters
Nexus Writer architecture
By woutdenolf
Nexus Writer architecture
- 95