Services
Services are long-running processes that perform specific functions or sets of functions in the background.
Services are similar to Apps, with the primary difference being that you can specify the port on which your Service listens. Both Apps and Services can host a web server that listens on a specified port, however, in case of Apps the port is chosen automatically. Unlike Services, Apps also appear as round, colorful buttons on the main page or in Dev / Pre Apps that you can access in the browser once deployed.
After deploying a service, you can talk to it from your IDE or any other runnable residing on the platform, be it an App, a Batch Job or an Excel Add-in.
Note – While the example below uses a Flask-based web server to respond to HTTP requests, it is not a requirement. You can serve anything in your service (or run any arbitrary code without even serving anything) as long as it has a service entrypoint defined:
def __service_main__(port):
Using Services
To be able to communicate with a running service knowing its name in Datatailr (find it in the Services tab of the Job Scheduler), it is first required to obtain its host and port. An example of a simple GET request in Python –
import dt.service
import requests
host, port = dt.service.service_host_and_port('My Service')
url = f'http://{host}:{port}'
response = requests.get(url, timeout=10)
print(response.text)
Creating Services
Steps that are required to create and deploy a Service are similar to those of the App deployment process – we need to create a .py
file with its logic (Step 1), package it (Step 2), build an image with the package (Step 3) and use it to deploy the runnable (Step 4). Don't worry – it is easier than it sounds.
-
Writing Code
Below is the implementation of a Flask service that serves as a simple key-value store –
from flask import Flask, request, jsonify import sys data_store = {} app = Flask(__name__) @app.route('/', methods=['GET']) def index(): return "Hello World Service!" @app.route('/__health_check__.html', methods=['GET']) def health_check(): return 'OK' @app.route('/get', methods=['GET']) def get_value(): key = request.args.get('key') if key in data_store: return jsonify({key: data_store[key]}) else: return jsonify({"error": "Key not found"}), 404 @app.route('/set', methods=['POST']) def set_value(): if not request.is_json: return jsonify({"error": "Invalid input, JSON required"}), 400 data = request.get_json() if 'key' not in data or 'value' not in data: return jsonify({"error": "Both 'key' and 'value' fields are required"}), 400 key = data['key'] value = data['value'] data_store[key] = value return jsonify({"message": "Value set successfully"}) # the service entrypoint definition def __service_main__(port): app.run('0.0.0.0', port=int(port), debug=False) # this block makes the service runnable in your IDE for debugging purposes if __name__ == '__main__': __service_main__(12345)
Feel free to test the service in your IDE before proceeding to the deployment. To do so, run the above file from the terminal:
python service.py
. Alternatively, click the "Run Python File" button in the top-right corner of your IDE. You may need to specify a different port value if12345
is in use already. -
Packaging Code
Once you are happy with results, build a package with your service as described in Step 2 of the app deployment process.
-
Building an Image
Include the package into a container image as described in Step 3 of the app deployment process.
-
Deploying the Service
Once the image is built, follow Step 4 of the app deployment process to deploy the service. The only difference with that tutorial would be using the Services tab of the Job Scheduler instead of the Apps tab.
To learn more about Services deployment, see:
Updated 7 months ago