
The Invocation Flow – from HTTP request to result.
In the previous article, we introduced the architecture behind evrtng Functions. Now let’s look at what actually happens when you call a function – step by step through the entire stack. From the HTTP request through authentication and message queue to the pod that executes your code and returns the result.
The Invocation Flow
- HTTP request hits Traefik: Your request – whether via CLI, SDK, or direct HTTP – reaches Traefik first, our edge router. TLS is terminated here and Let’s Encrypt certificates are managed automatically.
- APISIX handles the gateway: Behind Traefik sits APISIX, our API gateway. Rate limiting, billing logs, and abuse protection all come together here.
- Nginx distributes to controllers: Only behind APISIX does Nginx come into play as a reverse proxy. It distributes incoming requests evenly across the controller replicas.
- Controller authenticates: The controller validates your credentials against CouchDB. Namespace, API key, and permissions are checked – only when everything matches does it proceed.
- Action code is loaded: The controller fetches the action code from CouchDB. This can be JavaScript, Python, Java, or any other supported language – the platform is polyglot.
- Load balancer selects invoker: The integrated load balancer checks all available invokers and selects the one with the lowest load. This distributes traffic evenly.
- Kafka message: The controller publishes a message with action code, parameters, and metadata to Kafka. As soon as Kafka acknowledges the message, you receive an activation ID.
- Invoker takes over: The invoker picks the message from Kafka, spawns a Kubernetes pod with the appropriate runtime, injects the code, and executes it.
- Result: The result is stored in CouchDB, the pod is destroyed. You can retrieve the result via the activation ID – synchronously (blocking) or asynchronously (non-blocking).
This entire flow is based on the Apache OpenWhisk architecture, which we have adapted and optimized for evrtng.
A typical evrtng function
// evrtng Functions – Event-Driven Serverless
async function main(params) {
const start = Date.now();
const event = params.trigger || 'manual';
const timestamp = new Date().toISOString();
const result = await processEvent({
type: event,
data: params.payload,
timestamp
});
return {
statusCode: 200,
body: {
processed: true,
eventType: event,
result: result.summary,
executionTime: Date.now() - start
}
};
}
An async function main(params) – the entry point of every evrtng function. The platform takes care of containers, scaling, logging, and monitoring. You only write the logic.
How we run your functions securely

Each function execution in an isolated Kubernetes pod.
- Process isolation: Each function runs in its own process namespace. No access to memory or files of other functions.
- Network isolation: No direct access between containers possible. Strict network policies prevent lateral movement.
- Ephemerality: Containers are destroyed after each execution. No persistent state, always a clean environment.
- Resource limits: CPU, memory, and execution time are limited per container. A runaway function cannot affect the host.
Warm Containers
When the invoker receives a message from Kafka, it first checks whether a warm container is available. Warm means: already initialized with the correct runtime, ready for immediate code execution. This reduces cold starts significantly – often from several seconds to double-digit milliseconds. If no warm container is available, a new one is spawned and the code is injected via an internal HTTP interface.
The warm container mechanism makes OpenWhisk – and thus evrtng Functions – competitive in terms of latency. Frequently called functions benefit massively, as their containers are kept in the pool. Rarely used functions are created on demand. This is a good compromise between performance and resource efficiency – and one of the reasons why we chose this architecture.
