The Section 1 / Section 2 Model¶
Every pod's app.py has exactly two sections, clearly marked with comments. This is not a convention — it is a design constraint enforced by every template.
Section 1 — Business Logic (yours to modify)¶
Section 1 contains hook functions. The WoSP networking layer in Section 2 calls these hooks at specific lifecycle points — when a message arrives, when the auto-trigger fires, when all N upstream messages have been collected.
Each template ships with stubs that pass the payload through unchanged:
# ── SECTION 1: Business Logic (yours to modify) ─────────────────────
def on_trigger(payload, headers):
# Stub: pass through unchanged
return payload
# ── END SECTION 1 ────────────────────────────────────────────────────
Replace the stub body with your logic. The function signature stays the same — on_trigger always receives (payload, headers) and returns a dict. Everything else is yours:
# ── SECTION 1: Business Logic (yours to modify) ─────────────────────
import os
def on_trigger(payload, headers):
api_key = headers.get("x-api-key")
if api_key != os.environ.get("EXPECTED_KEY"):
raise ValueError("Unauthorized")
return {"task_id": str(uuid.uuid4()), "data": payload}
# ── END SECTION 1 ────────────────────────────────────────────────────
The WoSP layer never changes. Your business logic changes freely.
Section 2 — WoSP Networking (do not modify)¶
Section 2 is the networking layer. It contains:
- The
aiohttpserver that listens for inbound WoSP messages - The
asyncioqueue and task dispatch loop - Envoy egress forwarding configuration
/triggerand/outputPinhole endpoints (boundary pods only)FAN_INaggregation state (Aggregator pods)- The auto-trigger coroutine that fires 5 test messages at startup
Do not modify Section 2
Modifying Section 2 breaks inter-pod communication and voids WoSP security guarantees. If you need networking behavior that Section 2 doesn't provide, contact support@hopr.co.
The separation contract¶
Section 1 and Section 2 communicate through a small, stable interface. on_trigger receives the inbound payload and headers, and returns the outbound payload. The networking layer handles delivery. Your code never touches Envoy, WoSP, or Kubernetes directly.
This means you can develop and test Section 1 logic independently of the infrastructure. The hook functions have no dependencies on WoSP internals.
The auto-trigger runs your Section 1 code immediately
The auto-trigger in Section 2 calls on_trigger() with a synthetic payload at startup. Your Section 1 code runs on the very first deployment. Make sure your hook handles the default stub payload correctly before replacing it with production logic.