Open jjsaunier opened 6 years ago
There is indeed a very simple way:
bonobo.run(...)
call returns an instance of bonobo.execution.contexts.graph.GraphExecutionContext
that contains the (finished) execution state. You can retrieve it and iterate on the node execution contexts to get each node's statistics. How you aggregate them is up to you, here is a way to do it in your main block, inspired by the code in the console plugin:
if __name__ == '__main__':
parser = bonobo.get_argument_parser()
with bonobo.parse_args(parser) as options:
context = bonobo.run(
get_graph(**options),
services=get_services(**options)
)
for i in context.graph.topologically_sorted_indexes:
node = context[i]
print(node.get_statistics_as_string(), node.get_flags_as_string())
Never thought about having a "slack status", although it sounds so evident it is a simple and nice idea. It would fit a small plugin (like in bonobo.plugins.slack), if you code something, would you mind sharing/ contributing it back to bonobo ?
No problem, but I have no idea how to bundle a plugin for bonobo so I might need your help to achieve it :D Thanks for your answer
That's indeed something that is not well documented, especially because it was not very stabilized pre 0.6. I think this is less the case, now, but I still need to write documentation around that.
I'll try to explain it simply here and see if it's sufficient.
Plugins are classes that will be instanciated by a bonobo execution. By default, it will use ConsoleOutputPlugin
(if we're in an interactive terminal runtime environment) and JupyterOutputPlugin
(if we're in a Jupyter notebook runtime environment).
Those classes should subclass bonobo.plugins.Plugin
(or implement register()
and unregister()
using the same prototype found in the base class).
The bonobo execution context will create an "event dispatcher" (whistle.EventDispatcher
) instance and send it to register
. This event dispatcher will be used to register listeners (a.k.a callbacks) that can react to certain events. I think you're familiar with symfony's event dispatcher component, so you should not feel lost here as it's basically a python rewrite (ok a while ago, things may have evolved), otherwise you can find some details here: https://python-whistle.github.io/
Here is the list of events currently available for your plugin to use:
bonobo.execution.events.START
: before execution workers startsbonobo.execution.events.STARTED
: after workers startedbonobo.execution.events.TICK
: every 0.25 seconds (not reliable, period may change)bonobo.execution.events.STOP
: before workers are stoppedbonobo.execution.events.STOPPED
: workers stoppedbonobo.execution.events.KILL
: kill requested (because of error, ctrl-c, ...)The listeners will get an ExecutionEvent
instance with a reference to the current graph execution context available as event.context
, that you can inspect to get execution status.
The unregister
method, even if not so much useful, should clean up the event dispatcher of self
-related listeners. May be usefull later if plugins get more dynamic.
Needless to say, a slack plugin should be configured, and I'm open to ideas to do that cleanly. But being a 12-factor lover, maybe environment is a good start (of course, not sufficient, I knew this time would come when type
instances would show limits, and probably we'd want object
instances instead at some point).
To end this tutorial, the way to use a plugin is to pass it to bonono.run()
call:
bonobo.run(..., plugins=[SlackPlugin])
Let me know if I can help.
P.S.: An example plugin is the one which displays the status to the console: https://github.com/python-bonobo/bonobo/blob/master/bonobo/plugins/console.py
I'll follow that, for slack configuration bonobo is running over a containerized architecture, so configuration is only over env vars :+1:
And i'm considering to use this underlaying library for slack communication : https://github.com/slackapi/python-slackclient
Sorry, what I meant is that probably configuring it "globally" (for one process) is ok-ish at first, but we need also to think about what happens if there is more than one slack config for one process, and thus pass the configuration to the plugin somehow (SlackOutputPlugin(user=os.environ.get(...), key=os.environ.get(...)).
I'll help on this part once you're there, as it may need to change a bit how plugins are handled.
yep, I'm on bonobo slack, so when I'll have something that work we could discuss about it, should be more easier.
Thanks
Did I close that ? Mmm not intended I guess.
And i'm considering to use this underlaying library for slack communication : https://github.com/slackapi/python-slackclient
Of course, official library is fine! But this should be an optional dependency, a.k.a a dependency user installs himself if he does want to use the plugin.
Although an HTTP POST handler may be sufficient?
To be honest is not my goal, I just want a things that work without a lot of effort. Consider it as first step that could be improve. I understand the point that this lib is a bit heavy to POST on rest API, but as optional plugin, is it a big deal ?
No it is not a big deal, and first step is also very good. Maybe I was a bit unclear, let me try to rephrase.
It is fine to have libraries in bonobo.contrib
import things that are not bonobo dependencies. Wanted to state that the slack client should not be added to bonobo's dependencies, still it can be used in a bonobo.contrib
module. Up to the user to install correct deps in his own project.
It is already the case for example with bonobo.contrib.google
which allows to define google oauth based services easily in bonobo, but the user is responsible of the deps installation.
Does that make sense ?
Hello,
There is a simple way to collect metrics ? like number of elements (in, out), timing, error (if happened) etc from graph ?
I have a slack service and I want to be able to report my scheduled jobs, to easily monitor what are done and most of cases if there are no failures
Thank you and nice work !