Consuming the APIΒΆ

In order to design implementations of services, we must poll the API regularly in order to let TopChef know that the server is still up. This will be done by sending PATCH requests without the Content-Type header and without a request body. The service_timeout parameter describes how much time will pass before TopChef considers a service dead. The best way to do this is by thread-based programming. For Python, the topchef_client will take care of polling the service.

An example of Python 2-compliant code that implements a service is given below. Python 3 programmers should avoid using this code, instead creating tasks for concurrent.futures. This will do a much better job of separating concerns of functionality (what the thing does) versus execution policy (how

the task is run).
import requests
from time import sleep
from threading import Thread

class Service(object):
    """
    Defines a service
    """
    def __init__(self, topchef_service_url):
        """
        Create two threads. One will be checking for new jobs, and one
        will be polling the service to make sure that it is not dead.
        Both threads are daemon (read "demon") threads. This means that
        these threads will not prevent the program from terminating, and
        will be terminated by the Python interpreter after all other
        non-daemon threads have been terminated.

        :param topchef_service_url: The URL to the
            ``/services/<service_id>`` endpoint of the TopChef API.
        """
        self._url = topchef_service_url
        self._polling_thread = Thread(
            target=self._checkin_loop
        )
        self._new_job_thread = Thread(
            target=self._new_job_loop
        )

        self._polling_thread.daemon = True
        self._new_job_thread.daemon = True

    def start(self):
        """
        Start all the background threads
        """
        self._polling_thread.start()
        self._new_job_thread.start()

    def stop(self):
        """
        Stop all the background threads
        """
        self._polling_thread.stop()
        self._new_job_thread.stop()

    def poll_service(self):
        """
        Poll the service
        """
        response = requests.patch(
            self._url
        )
        assert response.status_code == 200

    def check_for_new_jobs(self):
        """
        Check if there are new jobs. If there are, run the job callback
        with the new data
        """
        url_to_check = '%s/next' % self._url

        response = requests.get(
            url_to_check, headers={'Content-Type': 'application/json'}
        )

        if response.status_code == 200:
            self.handle_new_job(response.get_json())

    def handle_new_job(self, job_data):
        """
        Handler that does something with the new job

        :param job_data: The new job data
        """

    def _new_job_loop(self, polling_interval=3):
        """
        Run a loop to check for new jobs, polling every certain amount
        of seconds

        :param polling_interval: The time to elapse before checking for
            new jobs
        """
        while True:
            self.check_for_new_jobs()
            sleep(polling_interval)

    def _checkin_loop(self, polling_interval=30):
        """
        Check in with the service to let it know that it's not dead
        """
        while True:
            self.poll_service()
            sleep(polling_interval)