Python Broker Modules
Flux broker modules extend the broker with new services. Traditionally
modules are written in C as dynamic shared objects, but Flux also supports
modules written in Python. A Python broker module is a .py file that
defines either a mod_main() entry function or a single
BrokerModule subclass.
Loading a Python module
Python modules are loaded and removed with the same flux-module(1) commands used for C modules:
$ flux module load /path/to/mymod.py
$ flux ping mymod
$ flux module remove mymod
The module name defaults to the file's basename without the .py suffix
and may be overridden with --name:
$ flux module load --name myservice /path/to/mymod.py
The mod_main entry point
A Python broker module may define a top-level function named mod_main():
def mod_main(h, *args):
...
h is a flux.Flux handle connected to the broker. args
is a (possibly empty) tuple of strings passed after the module path on the
flux module load command line. The function must run the reactor
(directly or via BrokerModule) and return only after
the reactor exits.
Defining mod_main() explicitly is optional when using
BrokerModule — see Using BrokerModule below.
Using BrokerModule
BrokerModule is a base class that handles the
boilerplate of registering message handlers, managing the reactor, and
looking up the module name. Subclass it and use the
request_handler() and
event_handler() decorators to declare handlers:
from flux.brokermod import BrokerModule, event_handler, request_handler
class MyModule(BrokerModule):
@request_handler("info")
def info(self, msg):
self.handle.respond(msg, {"name": self.name})
@event_handler("shutdown", prefix=False)
def on_shutdown(self, msg):
self.stop()
When a module file contains exactly one BrokerModule
subclass and no mod_main(), the loader synthesizes the entry point
automatically as MyModule(h, *args).run(), so no explicit
mod_main() is required. If multiple subclasses are present,
mod_main() must be defined to resolve the ambiguity:
def mod_main(h, *args):
MyModule(h, *args).run()
Handler methods receive a Message object. For request
handlers, call flux.Flux.respond() on the handle to send a response.
By default each handler's topic is prefixed with the module name, so
@request_handler("info") registers mymod.info. Pass
prefix=False to use the topic string as-is.
By default, only requests from the instance owner are delivered to a handler.
Pass allow_guest=True to also accept requests from non-owner users:
@request_handler("status", allow_guest=True)
def status(self, msg):
self.handle.respond(msg, {"running": True})
The handle property returns the
flux.Flux handle, giving full access to the Flux Python API for
RPCs, KVS operations, timers, and other watchers.
Logging
BrokerModule provides a
BrokerLogger instance as self.log. Use the
convenience methods to emit log messages without importing syslog:
self.log.info("module started")
self.log.error(f"handler failed: {exc}")
The full set of methods mirrors syslog severity levels: debug, info,
notice, warning, error, critical, alert, and emerg.
Log messages appear in flux-dmesg(1) and the broker's stderr.
By default all messages are forwarded to the ring buffer and the broker's
global log level acts as the filter — consistent with C module behaviour.
Subclasses may tighten the threshold by setting self.log.level:
self.log.level = "info" # suppress debug messages
Error handling
If run() raises OSError, or if
mod_main() raises any exception, the broker treats the module as
having exited with an error and logs a module runtime failure message.
Use stop_error() to signal an error from
within a handler.
Module arguments
Arguments passed after the module path at load time are available as
args in mod_main() and as
args on a BrokerModule
instance:
$ flux module load /path/to/mymod.py --verbose --count=4
def mod_main(h, *args):
# args == ('--verbose', '--count=4')
MyModule(h, *args).run()
Arguments are split on whitespace; quoting is not supported.
API reference
- class flux.brokermod.BrokerModule(h, *args)
Base class for Python broker modules.
Subclass this and use the
request_handler()andevent_handler()decorators to register message handlers, then callrun()to start the reactor. Handler topics are automatically prefixed with the module name unlessprefix=Falseis passed to the decorator.Example:
from flux.brokermod import BrokerModule, event_handler, request_handler class MyModule(BrokerModule): @request_handler("info") def info(self, msg): self.handle.respond(msg, self.name) @event_handler("panic") def panic(self, msg): self.stop_error()
When this is the only
BrokerModulesubclass in the file and nomod_main()is defined, the loader synthesizes the entry point automatically. An explicitmod_main()is only needed to resolve ambiguity when multiple subclasses are present.- property args
Tuple of module arguments passed at load time.
- debug_test(flag, clear=False)
Test a module debug bit, optionally clearing it.
Returns True if the bit identified by flag is set. If clear is True the bit is atomically cleared after being read. Bits are set externally via
flux module debug --setbit N <module-name>.
- property name
The module name as assigned by the broker.
- run()
Run the reactor until stopped.
Raises
OSErrorif the reactor was stopped with an error (e.g. viastop_error()) or if a Python exception was set on the handle during a callback.
- set_running()
Signal to the broker that the module is now running.
Call this before performing synchronous initialization in
run()to allowflux module loadto return instead of waiting for the reactor to start. See flux_module_set_running(3).
- flux.brokermod.request_handler(topic, prefix=True, allow_guest=False)
Decorator to register a method as a request handler.
The handler is invoked with (self, msg) when a request matching
<module_name>.<topic>is received. Ifprefix=False, the topic is used as-is without prepending the module name. Ifallow_guest=True, requests from non-owner users (FLUX_ROLE_USER) are also accepted.
- flux.brokermod.event_handler(topic, prefix=True)
Decorator to register a method as an event handler.
The handler is invoked with (self, msg) when an event matching
<module_name>.<topic>is received. Ifprefix=False, the topic is used as-is without prepending the module name.