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)