# The Lifecycle Contract for Data Overlays in the DataLayerManager: 4 States Explained

> Understand the data overlay lifecycle contract in DataLayerManager. Explore its four states disabled enabling enabled and disabling for safe, race-condition-free transitions.

- Repository: [Bilawal Sidhu/gods-eye-view](https://github.com/bilawalsidhu/gods-eye-view)
- Tags: deep-dive
- Published: 2026-08-29

---

**The DataLayerManager in the `gods-eye-view` repository enforces a strict lifecycle contract that moves every data overlay through `disabled`, `enabling`, `enabled`, and `disabling` states, using a serial queue and deterministic event pipeline to prevent race conditions and guarantee safe transitions.**

The `DataLayerManager` class defined in [`src/data/manager.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/data/manager.js) governs every real-time data overlay rendered on the CesiumJS globe in `bilawalsidhu/gods-eye-view`. Its **lifecycle contract for data overlays** specifies exactly how an overlay advances from initialization through activation to teardown, while an **“uncertain” flag** captures any transition that fails or aborts. Understanding these states and their enforcement mechanisms is essential for building reliable UI controls and custom data modules.

## Four Primary Lifecycle States

The contract defines four mutually exclusive states stored in the `lifecycleState` field, declared at `src/data/manager.js#L78-L88`.

### disabled

This is the default and terminal rest state. An overlay in the **disabled** state is fully off, releases resources, and does not render. The manager sets this state after a successful `disable()` call or during initialization.

### enabling

The **enabling** state means the manager is actively executing the enable sequence: `init` → `enable` → first `update`. The helper `_setLifecycleTransition` at `src/data/manager.js#L62-L71` records this transition and immediately notifies listening UI panels via `_refreshTogglePanel`.

### enabled

Once the enable sequence completes without error, `_settleLifecycle` at `src/data/manager.js#L74-L85` finalizes the entry as **enabled**. In this state the overlay is visible, actively polling for periodic updates, and fully integrated with the CesiumJS globe.

### disabling

The **disabling** state indicates an in-progress teardown. The manager enters this state through `_setLifecycleTransition(..., 'disabling')` while the overlay module’s `disable` logic runs.

### lifecycleUncertain Flag

Whenever a lifecycle step throws an exception or returns `false`—such as a rejected `enable`, `disable`, or `init`—the manager sets `entry.lifecycleUncertain = true`. According to the contract comment block at `src/data/manager.js#L15-L21`, this flag signals that the overlay’s authoritative state cannot be trusted and the transition should be treated as failed.

## Serial Queue and Phase Pipeline Enforcement

The lifecycle contract is enforced by a **serial queue** stored on each overlay entry as `entry.toggleChain`. This queue guarantees that only one lifecycle transition runs at a time for a given overlay, eliminating race conditions like double-polling or rapid enable-then-disable glitches.

Each transition follows a deterministic six-phase pipeline:

1. **Visibility-Will-Change** – The manager emits a `visibility-will-change` event so listeners can prepare.
2. **Guard Check** – `_visibilityBlockReason` may abort the transition before any module code runs.
3. **Lifecycle Transition** – `_setLifecycleTransition` records the new state (`enabling` or `disabling`) and refreshes toggle panels.
4. **Module Lifecycle Calls** – The overlay’s module receives ordered calls such as `entry.module.init()`, `entry.module.enable()`, `entry.module.update()`, or `entry.module.disable()`. Concrete implementations like the OpenSky traffic feed in [`src/data/traffic.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/data/traffic.js) implement these hooks.
5. **Error Handling** – Any thrown exception or rejected promise triggers a `visibility-failed` event and sets `entry.lifecycleUncertain = true`.
6. **Settlement** – On success, `_settleLifecycle` records the final `enabled` or `disabled` state and clears uncertainty.

Event emission for these phases is centralized at `src/data/manager.js#L490-L517`.

## Public API for Data Overlay Lifecycle Control

The contract is surfaced through two public methods that both return promises resolving only after the lifecycle settles.

### setEnabled

`setEnabled(layerId, shouldEnable, options)` requests an absolute state change. Pass `true` to activate an overlay or `false` to deactivate it.

```javascript
// Enable the OpenSky traffic overlay
await dataManager.setEnabled('openSky', true, {
  origin: 'user',
  notificationToken: 'ui-button',
});

// Disable the same overlay
await dataManager.setEnabled('openSky', false, {
  origin: 'user',
  notificationToken: 'ui-button',
});

```

### toggle

`toggle(layerId, options)` flips the current effective visibility without requiring the caller to know the existing state. Implemented at `src/data/manager.js#L174-L190`, it delegates to the same internal pipeline used by `setEnabled`.

```javascript
// Toggle the overlay relative to its current state
await dataManager.toggle('openSky', { origin: 'user' });

```

Both methods return a promise that resolves after the manager has moved through the appropriate lifecycle phases, guaranteeing the overlay is either fully active or fully inactive.

## Event-Driven State Synchronization

UI components such as those in [`src/ui.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/ui.js) consume a structured event stream to stay synchronized with the lifecycle contract. The manager emits the following events during transitions:

- `visibility-will-change` – Fired before the guard check and module calls begin.
- `visibility` – Fired after successful settlement.
- `visibility-failed` – Fired when a lifecycle step throws or rejects.
- `visibility-cancelled` – Fired when a transition is aborted by user action or logic.
- `visibility-blocked` – Fired when `_visibilityBlockReason` prevents the transition.

Listeners can use these events to update toggle buttons, persist user preferences, or display error indicators without polling the manager directly.

## Summary

- The **DataLayerManager** in [`src/data/manager.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/data/manager.js) defines a strict **lifecycle contract for data overlays** with four primary states: `disabled`, `enabling`, `enabled`, and `disabling`.
- A **serial queue** (`entry.toggleChain`) prevents concurrent transitions and eliminates race conditions.
- The six-phase pipeline includes event emission, guard checks, state recording via `_setLifecycleTransition`, module hooks, error handling, and final settlement via `_settleLifecycle`.
- The **uncertain flag** (`entry.lifecycleUncertain`) marks entries where a lifecycle step failed or returned `false`.
- Public methods `setEnabled` and `toggle` return promises that resolve only after the lifecycle settles, providing a safe async boundary for UI code.

## Frequently Asked Questions

### What happens if an overlay fails during the enable sequence?

If `init`, `enable`, or the first `update` throws or returns `false`, the manager emits a `visibility-failed` event and sets `entry.lifecycleUncertain = true` according to `src/data/manager.js#L74-L85`. The overlay does not reach the `enabled` state, and the entry remains in an untrustworthy condition until the next successful transition.

### How does the DataLayerManager prevent rapid toggle race conditions?

Each overlay entry owns a **serial queue** (`entry.toggleChain`) that chains lifecycle transitions sequentially. Because the pipeline enforces one transition at a time, rapid calls to `setEnabled` or `toggle` cannot overlap or execute out of order, preventing double-polling and visual glitches.

### What is the difference between `setEnabled` and `toggle`?

`setEnabled(layerId, shouldEnable)` drives the overlay toward an absolute boolean state and is used when the caller already knows the desired outcome. `toggle(layerId)`, defined at `src/data/manager.js#L174-L190`, determines the current effective visibility and then delegates to the same internal pipeline to flip it, making it ideal for simple button interactions.

### Which lifecycle events should a UI panel listen for?

Panels should listen for `visibility-will-change` to show loading indicators, `visibility` to confirm active state, `visibility-failed` to display errors, and `visibility-blocked` to explain why a transition was prevented. The [`src/ui.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/ui.js) file demonstrates this pattern by reacting to these events to refresh controls and panels.