Skip to content

TheRacetrack/job-runner-python-lib

Repository files navigation

Racetrack Job Runner library

This is a Python library that takes the Racetrack job and allows to run it in an API server. This runner (aka "wrapper") embeds given Python class in a REST server and adds extra features.

The library can be imported and run locally without using Racetrack services at all. Nevertheless, it is compatible with Racetrack standards and to run it there, you can pack your Job into a Dockerfile and deploy it to Racetrack, using generic "dockerfile" job type. Moreover, the outcome Docker image is nothing special, but just a regular API server. It can be tested locally and deployed anywhere else.

Check out Changelog to find out about notable changes.

Installation

You can locally install this Job runner to your local environment by doing:

pip install racetrack-job-runner

or

pip install "git+https://github.com/TheRacetrack/job-runner-python-lib.git@master"

This will install racetrack_job_runner CLI executable along with racetrack_job_wrapper module that can be imported later on.

Example 1: Run Python class with CLI executable

Create a sample Job class job.py like this:

import math

class Job:
    def perform(self, number: int) -> bool:
        """Check if a number is prime"""
        if number < 2:
            return False
        for i in range(2, int(math.sqrt(number)) + 1):
            if number % i == 0:
                return False
        return True

    def docs_input_example(self) -> dict:
        """Return example input values for this model"""
        return {'number': 7907}

Now you can run it on localhost inside an API server by calling this command in the terminal:

racetrack_job_runner run job.py

This will run your Job at 0.0.0.0:7000. You can visit it in your browser.

This runner does a lot of things, including:

  • Serve a Job at HTTP API server. It calls your Python def perform method whenever it receives a request to /api/v1/perform.
  • Serve automatically generated SwaggerUI documentation
  • Measure and serve Prometheus metrics at /metrics endpoint, reporting:
    • how many times the job was called
    • how long it took to call the job
    • how many errors have occurred
  • Map Job's methods to auxiliary endpoints
  • Serve static resources
  • Serve Custom Webview UI (if defined in a Job's entrypoint)
  • Serve empty API server, responding to liveness and readiness probes, while loading the Job
  • Concurrent requests cap
  • Make chain calls to other jobs
  • Structured logging
  • Keep record of a caller in the logs
  • Show exemplary input payload in documentation (if defined in a Job's entrypoint)

Example 2: Run from Python code

Alternatively, you can launch the job runner from your Python code. See a sample dockerfile job using this library in action.

Assuming you have a Job class job.py, you can run it inside an API server (and provide a lot of extra features). Call racetrack_job_wrapper.standalone.serve_job_class function in your Python program, combined with your Job class:

main.py

from racetrack_job_wrapper.standalone import serve_job_class
from job import Job

def main():
    serve_job_class(Job)

if __name__ == '__main__':
    main()

Execute python main.py and this will run your Job at 0.0.0.0:7000 just as in the example 1.

Running modes

There are several ways to run the same job.

1. Run on localhost with CLI executable

racetrack_job_runner run sample/dockerfiled/job.py

2. Run on localhost from Python

cd sample/dockerfiled
export JOB_NAME=primer JOB_VERSION=0.0.1
python main.py

3. Run in Docker

cd sample/dockerfiled &&\
docker buildx build -t sample-primer-job:latest -f Dockerfile .
docker run --rm -it --name sample-primer-job -p 7000:7000 sample-primer-job:latest

4. Run on Racetrack

racetrack deploy sample/dockerfiled

Job configuration

You may tweak additional features of your job by specifying extra fields in a job.yaml manifest:

jobtype_extra:
  max_concurrency: 1
  max_concurrency_queue: 10
  home_page: '/api/v1/webview'

Manifest YAML will be passed as environment variable to the Job by Racetrack's infrastructure plugin. That's how this library can access this configuration.

Concurrent requests cap

Maximum number of concurrent requests can be limited by jobtype_extra.max_concurrency field: By default, concurrent requests are unlimited. Setting max_concurrency to 1 will make the job process requests one by one. Overdue requests will be queued and processed in order.

Having such concurrency limits may cause some requests to wait in a queue. If a throughput is higher than the job can handle, the queue will grow indefinitely. To prevent that, you can set jobtype_extra.max_concurrency_queue to limit the queue size. When the queue is full, the job will return 429 Too Many Requests status code.

Example (1 request at a time, with up to 10 requests waiting in a queue):

jobtype_extra:
  max_concurrency: 1
  max_concurrency_queue: 10

Home page

You can configure the home page of your job. Home page is the one you see when opening a job through the Dashboard or at the root endpoint. By default, it shows the SwaggerUI page. Now you can change it, for instance, to a webview endpoint:

jobtype_extra:
  home_page: '/api/v1/webview'

Caller name

Setting environment variable LOG_CALLER_NAME=true allows you to keep record of a caller in the job's logs.

ENV LOG_CALLER_NAME "true"

This will add caller identity (username or ESC name) to every log entry.

Logging

To produce logs, use logging module inside your job:

import logging
logger = logging.getLogger(__name__)

class JobEntrypoint:
    def perform(self):
        logger.info('something happened')

Comparison with Python job type

This library has been originated from Python job type plugin. If you need to recreate some of its features, take a look at the job Dockerfile template and do the same in your individual Job's Dockerfile.

In contrast to Python job type plugin, you directly call the utility functions in your code, you bind the things together. This is opposed to a job type, where the framework calls your code. This project transitions from a framework into a library approach, giving you more control.

Packages

No packages published

Languages