# Service Registration & Heartbeat

# Service Registration & Heartbeat

<details>
<summary>Relevant source files</summary>

The following files were used as context for generating this wiki page:

- [src/ports/service-registry-port.ts](src/ports/service-registry-port.ts)
- [src/service/__tests__/service-registrar.test.ts](src/service/__tests__/service-registrar.test.ts)
- [src/service/service-registrar.ts](src/service/service-registrar.ts)
- [src/service/service-registry.ts](src/service/service-registry.ts)

</details>



The Service module provides a standardized mechanism for microservices to announce their presence and maintain an active status within a central `service_registry` table. This module facilitates service discovery by ensuring that service metadata (base URLs and available endpoints) is kept up-to-date and that stale service entries can be identified via heartbeat timestamps.

### Service Data Shape

The module defines a shared interface, `IServiceRegistry`, which represents the data structure stored in the database. To maintain database agnosticism, this interface is a plain TypeScript interface without decorators or dependencies on specific ORMs [src/service/service-registry.ts:4-11]().

| Property | Type | Description |
| :--- | :--- | :--- |
| `code` | `string` | Unique identifier for the service (e.g., "emailsender"). |
| `base_url` | `string` | The root URL where the service is reachable. |
| `endpoints` | `Record<string, unknown>` | A map of functional endpoints exposed by the service. |

**Sources:** [src/service/service-registry.ts:12-16]()

---

### The ServiceRegistrar Class

The `ServiceRegistrar` is the primary orchestrator for service lifecycle events. It handles the initial registration (upsert logic) and the background heartbeat interval. It is designed to be DB-agnostic by depending on the `ServiceRegistryPort` rather than a specific Data Access Layer (DAL) [src/service/service-registrar.ts:11-19]().

#### Configuration
The registrar is configured via the `ServiceRegistrarConfig` object:
*   `serviceCode`: The unique name of the service.
*   `baseUrl`: The current address of the service instance.
*   `endpoints`: Metadata describing available routes.
*   `heartbeatIntervalMs`: Frequency of heartbeat updates (defaults to 60,000ms if not provided) [src/service/service-registrar.ts:28-31]().

#### Registration Logic
When `register()` is called, the class performs an "upsert" against the provided port:
1.  It queries for an existing entry using `findByCode` [src/service/service-registrar.ts:35]().
2.  If the service exists, it calls `updateByCode` to refresh the `base_url` and `endpoints` [src/service/service-registrar.ts:38-42]().
3.  If no entry is found, it calls `insert` to create a new record [src/service/service-registrar.ts:45-49]().

#### Heartbeat Management
*   **`startHeartbeat()`**: Initializes a `setInterval` that periodically calls `updateHeartbeat()` [src/service/service-registrar.ts:64-67]().
*   **`updateHeartbeat()`**: Triggers a partial update of the `base_url`. This operation is designed to be resilient; it catches and logs database errors to prevent the service from crashing due to transient network or DB issues [src/service/service-registrar.ts:54-62]().
*   **`stopHeartbeat()`**: Clears the interval timer and nullifies the reference, ensuring a clean shutdown [src/service/service-registrar.ts:69-74]().

**Sources:** [src/service/service-registrar.ts:4-75](), [src/service/__tests__/service-registrar.test.ts:33-78]()

---

### Service Registry Port

The SDK interacts with the database through the `ServiceRegistryPort`. The consuming microservice must provide an adapter implementation that maps these calls to their specific database driver or ORM (e.g., TypeORM, Knex, or a custom DAL) [src/ports/service-registry-port.ts:6-9]().

**Service Registration Data Flow**

```mermaid
graph TD
    subgraph "SDK Core"
        SR["ServiceRegistrar"]
        SRP["ServiceRegistryPort (Interface)"]
    end

    subgraph "Consuming Microservice"
        Adapter["ServiceRegistryAdapter (Implementation)"]
        DB[("service_registry Table")]
    end

    SR -->|1. findByCode| SRP
    SR -->|2. insert OR updateByCode| SRP
    SRP -.->|Calls| Adapter
    Adapter -->|SQL Queries| DB
```

**Sources:** [src/ports/service-registry-port.ts:10-19](), [src/service/service-registrar.ts:20-25]()

---

### Implementation Mapping

The following diagram bridges the high-level registration concepts to the specific code entities defined in the SDK.

**Code Entity Mapping**

```mermaid
classDiagram
    class IServiceRegistry {
        <<interface>>
        +code: string
        +base_url: string
        +endpoints: Record
    }

    class ServiceRegistryPort {
        <<interface>>
        +findByCode(code)
        +insert(row)
        +updateByCode(code, row)
    }

    class ServiceRegistrar {
        -repo: ServiceRegistryPort
        -config: ServiceRegistrarConfig
        +register()
        +startHeartbeat()
        +updateHeartbeat()
        +stopHeartbeat()
    }

    ServiceRegistrar ..> IServiceRegistry : manages
    ServiceRegistrar o-- ServiceRegistryPort : uses
```

**Sources:** [src/service/service-registry.ts:12-16](), [src/ports/service-registry-port.ts:10-19](), [src/service/service-registrar.ts:20-75]()

---
