.. _intermediate-tutorial: Intermediate Tutorial ===================== This is an intermediate level tutorial. Condition Logic ---------------- Previously we have introduced some ways to schedule tasks. Sometimes the existing options are not enough and you need to compose a scheduling logic from multiple conditions. For such purpose, there are logical operations: - ``&``: *AND* operator - ``|``: *OR* operator - ``~``: *NOT* operator Using these are pretty simple: .. literalinclude:: /code/schedule/logic.py :language: py We used conditions ``true`` and ``false`` but you may replace these with other conditions (ie. ``daily``) from previous examples. You may also add parentheses for extra logic: .. code-block:: python @app.task('(true & false) | (~false)') def do_constantly(): ... Scheduling strings may become quite long some times. The strings can also be broken down to multiple lines: .. code-block:: python @app.task(''' daily between 07:00 and 10:00 & (time of week on Monday | time of week on Friday) ''') def do_on_monday_or_friday_morning(): ... Pipelining with Conditions -------------------------- Tasks can also be piped by setting a task to run after another, setting a output of a task as the input for another or both. .. literalinclude:: /code/snippets/pipeline.py :language: py The second task runs when the first has succeeded and the input argument gets the value of the output argument of the first task. Parameterize Tasks ------------------ Parameters are key-value pairs passed to the tasks. The value of the pair is called *argument*. The argument can be derived from the return of another task, from the return value of a function or a component of the scheduling framework. There are also two scopes of parameters: session level and task level. When a task is run, the argument is looked from the task level arguments and then from the session level arguments. Here is an illustration: .. code-block:: python from redengine.args import Arg # Setting arguments to the session app.params( my_arg='Hello world' ) @app.task("every 10 seconds") def do_things(item = Arg('my_arg')): ... We set a session level argument (``my_arg``) and we used that in the task ``do_things``. The session level argument is turned as a task level argument with ``Arg('my_arg'`)``. This argument can be reused in multiple tasks as it was set on session level. Setting an argument to task level only looks like this: .. code-block:: python from redengine.args import SimpleArg @app.task("every 10 seconds") def do_things(item = SimpleArg('Hello world')): ... ``SimpleArg`` is just a placeholder argument that is simply the value that was passed (which is ``'Hello world'``). In the example above the argument is not reusable in other tasks. Next we will cover some basic argument types that have more functionalities. Function Argments ^^^^^^^^^^^^^^^^^ Function arguments are arguments which values are derived from the return value of a function. To set a session level function argument: .. code-block:: python from redengine.args import FuncArg def get_item(): return 'hello world' @app.task("every 10 seconds") def do_things(item = FuncArg(get_item)): ... To set task level function argument: .. code-block:: python from redengine.args import Arg @app.param('my_arg') def get_item(): return 'hello world' @app.task("every 10 seconds") def do_things(item = Arg('my_arg')): ... Meta Argments ^^^^^^^^^^^^^ Meta arguments are arguments that contain a component of the scheduling system. These are useful when you need to manipulate the session in a task (ie. shut down the scheduler or add/delete tasks) or manipulate some tasks (ie. force running or change attributes). An example of the session argument: .. code-block:: python from redengine.args import Session @app.task("every 10 seconds") def manipulate_session(session = Session()): ... An example of the task argument: .. code-block:: python from redengine.args import Task @app.task("every 10 seconds") def manipulate_task(this_task=Task(), another_task = Task('do_things')): ... Customizing Logging Handlers ---------------------------- Red Engine uses `Red Bird's `_ `logging handler `_ for implementing a logger that can be read programmatically. Red Bird is a repository pattern library that abstracts database access from application code. This is helpful to create a unified interface to read the logs regardless if they are stored to a CSV file, SQL database or to a plain Python list in memory. As the logger is simply extension of `the logging library `_, you may add other logging handlers as well: .. code-block:: python import logging from redengine import RedEngine app = RedEngine() # Create a handler handler = logging.StreamHandler() handler.setLevel(logging.DEBUG) # Add the handler task_logger = logging.getLogger('redengine.task') task_logger.addHandler(handler) .. warning:: Make sure the logger ``redengine.task`` has at least one ``redbird.logging.RepoHandler`` in handlers or the system cannot read the log information. Reading from the Logs --------------------- Reading programmatically from the logs is easy due to unified querying syntax of Red Bird. Simply .. code-block:: python import logging task_logger = logging.getLogger('redengine.task') # Getting a RepoHandler for handler in task_logger.handlers: if hasattr(handler, "repo"): break # Query all logs from the handler handler.filter_by().all() Read more about the querying from `Red Bird's documentation `_