Skip to main content
Understanding how Edge Compute executes your functions helps you optimize performance and build reliable applications.

Overview

Edge Compute runs your functions in lightweight Linux containers. When a request arrives:
  1. Routing — Request is routed to the nearest edge location
  2. Container selection — An existing warm container handles the request, or a new one starts (cold start)
  3. Execution — Your function processes the request
  4. Response — Result is returned to the caller
  5. Keep-alive — Container stays warm for subsequent requests

Function Lifecycle

Cold Start Phase

When a function receives its first request or scales up, a new container initializes:
# Global initialization (runs once per container)
import json
from database import create_pool

# Expensive operations here — only run once
db_pool = create_pool()
cache = {}

# Function handler (runs per request)
async def handler(request):
    # Fast path — reuse initialized resources
    data = await request.json()
    result = await db_pool.query('SELECT * FROM users')
    return Response(json.dumps(result))
Cold start timeline:
  1. Container image pulled (cached at edge)
  2. Runtime initializes (Python/Go/Quarkus)
  3. Global code executes (imports, connections)
  4. First request handled

Warm Execution

Subsequent requests reuse the same container instance:
import httpx

# Global variables persist between requests
client = httpx.Client(timeout=10.0)

async def handler(request):
    # Fast execution — resources already initialized
    print(f"Request: {request.method} {request.path}")
    
    resp = client.get("https://api.example.com/data")
    return resp.json()

Container Recycling

Containers are recycled when:
  • Idle for extended periods (to free resources)
  • Memory limits approached
  • New deployment shipped
  • Platform scaling decisions
Don’t rely on container persistence for critical state. Use KV or external storage for data that must survive restarts.

Cold Start Optimization

Minimize cold start latency with these patterns:

1. Lazy Initialization

Defer expensive operations until needed:
# Bad — always initializes
ml_model = load_model('large_model.pkl')  # 2 seconds

def handler(request):
    return ml_model.predict(request.data)
# Good — only loads when needed
_ml_model = None

def get_model():
    global _ml_model
    if _ml_model is None:
        _ml_model = load_model('large_model.pkl')
    return _ml_model

def handler(request):
    if request.path == '/predict':
        return get_model().predict(request.data)
    return {"status": "ok"}

2. Minimize Dependencies

# Bad — imports everything
import pandas as pd
import numpy as np
import tensorflow as tf

# Good — import only what you need
from json import loads, dumps

3. Connection Pooling

# Initialize pool globally
from sqlalchemy import create_engine
from sqlalchemy.pool import QueuePool

engine = create_engine(
    DATABASE_URL,
    poolclass=QueuePool,
    pool_size=5,
    max_overflow=10
)

def handler(request):
    with engine.connect() as conn:
        result = conn.execute("SELECT * FROM users")
        return list(result)

Concurrency

Each container handles one request at a time by default. The platform automatically scales containers based on traffic:
Traffic: 100 requests/second

Platform scales to ~100 containers

Each container handles ~1 req/sec

Scaling Behavior

Traffic PatternPlatform Response
Traffic spikeNew containers start (cold starts)
Sustained loadContainers stay warm
Traffic dropsContainers gradually recycle
Zero trafficAll containers recycle after idle timeout

Request Timeouts

Functions have execution time limits:
TierTimeout
Default30 seconds
Extended60 seconds (configurable)
Handle timeouts gracefully:
import asyncio

async def handler(request):
    try:
        # Set timeout for 25 seconds (5 sec buffer before platform timeout)
        result = await asyncio.wait_for(
            long_running_operation(),
            timeout=25.0
        )
        return result
    except asyncio.TimeoutError:
        return {"error": "Operation timed out", "partial": get_partial_result()}

Triggers

Functions can be invoked by:

HTTP Requests

# func.toml
[edge_compute]
func_name = "my-api"

# Accessible at: https://my-api-{orgId}.telnyxcompute.com

Webhooks

Configure Telnyx services to call your function:
async def handler(request):
    event = await request.json()
    
    if event.get('event_type') == 'message.received':
        handle_incoming_message(event['data'])
    elif event.get('event_type') == 'call.initiated':
        handle_call(event['data'])
    
    return {"status": "ok"}

Cron Triggers (Coming Soon)

🔜 Scheduled execution via cron expressions is planned for a future release.

Graceful Shutdown

When containers recycle, your function receives a shutdown signal:
import signal
import sys

def shutdown_handler(signum, frame):
    # Clean up resources
    db_pool.close()
    cache.flush()
    sys.exit(0)

signal.signal(signal.SIGTERM, shutdown_handler)

Best Practices

  1. Initialize globally — Move expensive setup outside request handlers
  2. Keep handlers fast — Aim for < 100ms p99 latency
  3. Use connection pools — Reuse database/HTTP connections
  4. Handle errors gracefully — Return meaningful error responses
  5. Don’t store state in memory — Use KV or external storage for persistence
  6. Set appropriate timeouts — On outbound requests to prevent hanging

Next Steps

  • Bindings — Connect to Telnyx platform services
  • Limits — Understand resource constraints
  • Configuration — Set environment variables and secrets