pythonbottletelemetry

Telemetry in a Python Bottle API


I have a simple Python Bottle API used to support an iOS app. It is hosted on Heroku.

I use TelemetryDeck for analytics, so I want to send signals with each API call. I'm not using Node so cannot use their JS SDK and thus I have to send signals over HTTP.

Here is my function for sending telemetry signals.

def send_telemetry(type, success):
    url = TELEMETRY_DECK_URL
    headers = {
        "Content-Type": "application/json; charset=utf-8"
    }
    data = [
        {
            "isTestMode": "false",
            "appID": TELEMETRY_DECK_APP_ID,
            "clientUser": "apiProcess",
            "sessionID": "",
            "type": "API Called",
            "payload": {
                "api_type": type,
                "api_success": success
            }
        }
    ]
    response = requests.post(url, headers=headers, json=data)
    
    # Print to Heroku logs
    print(response.text)

Here is an example of where I call the telemetry method from an app route.

@app.get('/')
def example():
    # Other code
    if result:
        send_telemetry("type", "true")
        response.status = 200
        return make_response(result)
    else:
        send_telemetry("type", "false")
        response.status = 404
        return make_error("Error (404)")

This all works fine, but I am concerned that the telemetry method is running synchronously before Bottle returns a response, and of course it cannot run after the response is returned due to WSGI limitations.

Is there a way to asynchronously trigger an analytics method and not delay execution at the callsite in the route, so performance is not impacted. I'm happy for a "fire and forget" solution and don't need to receive a callback.

I looked at solutions using multithreading but they looked more complex than what I needed.


Solution

  • I actually got this working simply using the threading module.

    In my route handler I simply insert this code which generates a thread targeting my send_telemetry function. It runs in a separate thread as expected, and does not hold up execution of Bottle returning a response.

    import threading
    
    thread = threading.Thread(target=send_telemetry, args=["type", "true"])
    thread.start()