Skip to main content

System Architecture

This document describes the internal architecture of Integration Hub for Moodle (MIH), the responsibilities of each component, and the design decisions behind them.


High-Level Overview

MIH is structured around two independent but complementary execution paths:


Component Map

Core Layer

ClassNamespaceFileRole
mihlocal_integrationhubclasses/mih.phpMain orchestrator. Facade/Singleton. Public API for all plugins. Coordinates service resolution, circuit breaking, transport selection, retry, and logging.
mih_responselocal_integrationhubclasses/mih_response.phpImmutable value object. Wraps the result of every request regardless of transport.

Service Layer

ClassNamespaceFileRole
registrylocal_integrationhub\serviceclasses/service/registry.phpData access. CRUD operations for the local_integrationhub_svc table. Also initializes the circuit breaker record when a service is created.
circuit_breakerlocal_integrationhub\serviceclasses/service/circuit_breaker.phpFault tolerance. Tracks failure counts and manages CLOSED/OPEN/HALFOPEN state transitions. Reads/writes local_integrationhub_cb.
retry_policylocal_integrationhub\serviceclasses/service/retry_policy.phpResilience. Executes a callable with configurable retry attempts and exponential backoff.

Transport Layer

ClassNamespaceFileRole
contractlocal_integrationhub\transportclasses/transport/contract.phpInterface. Defines the execute() contract all drivers must implement.
httplocal_integrationhub\transportclasses/transport/http.phpREST driver. Uses native PHP cURL. Supports GET, POST, PUT, PATCH, DELETE.
amqplocal_integrationhub\transportclasses/transport/amqp.phpRabbitMQ driver. Uses php-amqplib. Publishes JSON messages to exchanges or queues.
amqp_helperlocal_integrationhub\transportclasses/transport/amqp_helper.phpAMQP utilities. Centralizes connection creation (plain and SSL) and queue declaration.
soaplocal_integrationhub\transportclasses/transport/soap.phpSOAP driver. Uses PHP's native SoapClient.
transport_utilslocal_integrationhub\transportclasses/transport/transport_utils.phpTrait. Shared helpers for building success_result and error_result arrays.

Event Layer

ClassNamespaceFileRole
observerlocal_integrationhub\eventclasses/event/observer.phpUniversal listener. Registered against \core\event\base to catch every event in Moodle. Performs rule lookup, deduplication, and adhoc task queuing.
webhook_receivedlocal_integrationhub\eventclasses/event/webhook_received.phpCustom event. Fired when an inbound webhook is received, allowing other plugins to react.

Task Layer

ClassNamespaceFileRole
dispatch_event_tasklocal_integrationhub\taskclasses/task/dispatch_event_task.phpAdhoc task. Processes one queued event: loads the rule, interpolates the template, calls the MIH API, handles DLQ on permanent failure.
consume_responses_tasklocal_integrationhub\taskclasses/task/consume_responses_task.phpScheduled task. Runs every minute. Consumes inbound messages from configured AMQP response queues.
queue_managerlocal_integrationhub\taskclasses/task/queue_manager.phpQueue utilities. Shared logic for queue monitoring and DLQ management.

Execution Paths

Path 1: Direct Plugin Call (Synchronous)

This path is synchronous — the calling plugin waits for the result. Use it when you need the response immediately (e.g., to validate data, get an ID, or display a result to the user).

Path 2: Event Bridge (Asynchronous)

This path is asynchronous — the user action completes immediately. The integration happens in the background. Use it for fire-and-forget notifications, webhooks, and event streaming.


Key Design Decisions

Facade Pattern (MIH)

mih is strictly a facade over the internal singleton instance. This provides a clean static API (mih::request()) while maintaining testability and state management internally.

Transport as Strategy Pattern

The transport layer uses the Strategy pattern via the contract interface. The MIH API selects the correct driver at runtime based on the service's type field. Adding a new transport (e.g., gRPC) requires only implementing contract and registering it in get_transport_driver().

Retry Inside Transport vs. MIH API

The retry logic lives in the MIH API (via retry_policy), not inside each transport driver. This keeps drivers simple and ensures consistent retry behavior regardless of transport.

Deduplication via Cache

Event deduplication uses Moodle's application cache (local_integrationhub/event_dedupe). The cache key is a SHA1 hash of eventname + objectid + userid + crud. This prevents duplicate adhoc tasks from being queued when the same logical event fires multiple times (e.g., due to Moodle's observer system calling the same event from multiple contexts).

DLQ After 5 Attempts

Moodle's adhoc task system has its own retry mechanism. dispatch_event_task tracks its own attempt counter in custom_data. After 5 total attempts, it stops rethrowing and instead writes the failed payload to local_integrationhub_dlq, preventing infinite retry loops.

Auto-purging Logs

The log table is automatically pruned after every write. The maximum number of entries is configurable (default: 500). This prevents unbounded database growth in high-traffic deployments.


Database Relationships

All foreign keys cascade on delete — removing a service cleans up all associated records.