Async execution with webhooks is designed for very long-running tasks (>30 minutes) that would otherwise timeout. The execution happens asynchronously, and results are delivered to your webhook endpoint when complete.
Overview
Async webhook execution is perfect for:
- ML model training (30+ minutes)
- Large dataset processing
- Video encoding/processing
- Long-running simulations
- Any task that exceeds normal timeout limits
Async webhook execution returns immediately with an execution_id. The agent executes code in the background and POSTs results to your callback URL when complete.
Basic Usage
Start async execution with a webhook callback:
from hopx_ai import Sandbox
sandbox = Sandbox.create(template="code-interpreter")
# Start async execution
response = sandbox.run_code_async(
code='''
import time
print("Starting long task...")
time.sleep(600) # 10 minutes
print("Task completed!")
''',
callback_url='https://your-app.com/webhooks/HopX-complete',
language='python',
timeout=1800 # 30 minutes max
)
print(f"Execution ID: {response['execution_id']}")
print(f"Status: {response['status']}")
print(f"Callback URL: {response['callback_url']}")
sandbox.kill()
Webhook Callback
Your webhook endpoint will receive a POST request when execution completes:
Python (Flask)
JavaScript (Express)
from flask import Flask, request
import hmac
import hashlib
app = Flask(__name__)
@app.route('/webhooks/HopX-complete', methods=['POST'])
def hopx_webhook():
# Verify signature (if secret provided)
signature = request.headers.get('X-HopX-Signature')
timestamp = request.headers.get('X-HopX-Timestamp')
# Verify signature if secret was provided
# secret = 'your-webhook-secret'
# expected_sig = hmac.new(
# secret.encode(),
# f"{timestamp}{request.data}".encode(),
# hashlib.sha256
# ).hexdigest()
# if signature != f"sha256={expected_sig}":
# return "Invalid signature", 401
# Process webhook payload
data = request.json
execution_id = data['execution_id']
status = data['status']
stdout = data.get('stdout', '')
stderr = data.get('stderr', '')
exit_code = data.get('exit_code', 0)
execution_time = data.get('execution_time', 0)
print(f"Execution {execution_id} completed with status: {status}")
print(f"Output: {stdout}")
if status == 'completed':
# Handle successful completion
process_results(execution_id, stdout)
else:
# Handle failure
handle_error(execution_id, stderr)
return "OK", 200
Signature Verification
Verify webhook signatures for security:
from hopx_ai import Sandbox
import hmac
import hashlib
sandbox = Sandbox.create(template="code-interpreter")
# Start async execution with signature secret
response = sandbox.run_code_async(
code='import time; time.sleep(600); print("Done")',
callback_url='https://your-app.com/webhooks/HopX-complete',
callback_signature_secret='your-webhook-secret-123',
language='python'
)
print(f"Execution ID: {response['execution_id']}")
# In your webhook handler:
# signature = request.headers.get('X-HopX-Signature')
# timestamp = request.headers.get('X-HopX-Timestamp')
# body = request.data
#
# expected = hmac.new(
# 'your-webhook-secret-123'.encode(),
# f"{timestamp}{body}".encode(),
# hashlib.sha256
# ).hexdigest()
#
# if signature == f"sha256={expected}":
# # Valid signature
# pass
Include custom headers in webhook callbacks:
from hopx_ai import Sandbox
sandbox = Sandbox.create(template="code-interpreter")
# Start async execution with custom headers
response = sandbox.run_code_async(
code='import time; time.sleep(600); print("Done")',
callback_url='https://your-app.com/webhooks/HopX-complete',
callback_headers={
'Authorization': 'Bearer your-api-token',
'X-Custom-Header': 'custom-value'
},
language='python'
)
print(f"Execution ID: {response['execution_id']}")
# Your webhook will receive:
# POST https://your-app.com/webhooks/HopX-complete
# Authorization: Bearer your-api-token
# X-Custom-Header: custom-value
# X-HopX-Signature: sha256=...
# X-HopX-Timestamp: 1698765432
Complete Example
Here’s a complete example with ML model training:
from hopx_ai import Sandbox
sandbox = Sandbox.create(template="code-interpreter")
# Start ML training with async webhook
response = sandbox.run_code_async(
code='''
import time
import random
print("Starting ML model training...")
print("Epoch 1/10...")
time.sleep(60)
for epoch in range(2, 11):
loss = random.uniform(0.1, 0.5)
accuracy = random.uniform(0.8, 0.95)
print(f"Epoch {epoch}/10 - Loss: {loss:.4f}, Accuracy: {accuracy:.4f}")
time.sleep(60)
print("Training completed!")
print("Model saved to /workspace/model.pkl")
''',
callback_url='https://your-app.com/webhooks/ml-training-complete',
callback_headers={
'Authorization': 'Bearer ml-api-token',
'X-Training-ID': 'training-123'
},
callback_signature_secret='ml-webhook-secret',
language='python',
timeout=3600, # 1 hour
env={
'WANDB_API_KEY': 'your-wandb-key',
'HF_TOKEN': 'your-huggingface-token'
}
)
print(f"✅ Training started")
print(f"Execution ID: {response['execution_id']}")
print(f"Status: {response['status']}")
print(f"Results will be posted to: {response['callback_url']}")
# Your webhook will receive results when training completes
sandbox.kill()
Webhook Payload
The webhook payload structure:
{
"execution_id": "abc123",
"status": "completed",
"stdout": "Task output...",
"stderr": "",
"exit_code": 0,
"execution_time": 600.123
}
Headers:
X-HopX-Signature: HMAC-SHA256 signature (if secret provided)
X-HopX-Timestamp: Unix timestamp
- Custom headers from
callback_headers
Best Practices
1. Always Verify Signatures
Use callback_signature_secret and verify signatures in your webhook handler to ensure requests are authentic.
2. Handle Timeouts
Set appropriate timeouts based on expected execution time. Default is 30 minutes, max is typically 1 hour.
3. Use Custom Headers
Include authentication tokens or identifiers in callback_headers for secure webhook processing.
4. Handle Both Success and Failure
Check the status field in webhook payloads to handle both successful completions and failures.
5. Store Execution IDs
Store execution_id when starting async execution to correlate webhook callbacks with your records.
Next Steps