Skip to content

Restructure Resource Hierarchy documentation to separate IResourceWithParent from lifecycle semantics #10897

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 25 additions & 27 deletions docs/specs/appmodel.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ graph LR
- [Importance of Polymorphism](#importance-of-polymorphism)
- [Resource Hierarchy and Parent‑Child Relationships](#resource-hierarchy-and-parent-child-relationships)
- [Lifecycle Containment](#lifecycle-containment)
- [Visual Grouping (Without Lifecycle Impact)](#visual-grouping-without-lifecycle-impact)
- [Manual Relationships — No Inference](#manual-relationships--no-inference)
- [Real-World Examples](#real-world-examples)
- [Values and References](#values-and-references)
Expand Down Expand Up @@ -387,61 +386,60 @@ Interfaces allow Aspire to remain **open, flexible, and adaptable** as new types

## Resource Hierarchy and Parent-Child Relationships

Aspire supports modeling **parent-child relationships** between resources to express ownership, containment, and grouping.
Aspire supports modeling parent-child relationships between resources to express ownership, containment, and grouping.

Parent-child relationships serve two purposes:
- **Lifecycle Containment**: The child's execution is tied to the parent's — starting, stopping, and failures cascade from parent to child automatically.
- **Dashboard Visualization**: The child appears **nested beneath** the parent in dashboards and visualizations, improving readability.
Parent-child relationships primarily serve to:
- Structural ownership and visualization: Expresses containment in the model and drives visual nesting in dashboards and visualizations.
- Optional lifecycle coordination (opt-in): Some resource types choose to coordinate start/stop behavior relative to other resources. This behavior is separate from the parent-child structure and is not implied by any single interface.

---

### Lifecycle Containment
Aspire provides two ways to declare parent-child relationships:

When a resource implements the `IResourceWithParent` interface, it declares **true containment** — meaning its lifecycle is controlled by its parent:
**`IResourceWithParent` (static declaration)**: When a resource implements this interface, it statically declares a parent-child relationship. This establishes structural containment and visual nesting. `IResourceWithParent` implies `WithParentRelationship()`.

- **Startup**: The child resource will only start after its parent starts (though readiness is independent).
- **Shutdown**: If the parent is stopped or removed, the child is also stopped automatically.
- **Failure Propagation**: If a parent enters a terminal failure state (`FailedToStart`, etc.), dependent children are stopped.
**`WithParentRelationship()` (dynamic declaration)**: This method dynamically declares a parent-child relationship during resource construction, affecting only dashboard layout and visual grouping.

> **Example:**
> A logging sidecar container is tied to the lifecycle of a main application container — if the main app stops, the logging sidecar is also terminated.
Both approaches are purely structural and do not impose any lifecycle behavior.

---

### Visual Grouping (Without Lifecycle Impact)
### Lifecycle Containment

Lifecycle coordination is optional and separate from structural parent-child relationships. It is implemented on a case-by-case basis by specific resource types or integrations.

Aspire also supports **visual-only parent-child relationships** using the `WithParentRelationship()` method during resource construction.
Common lifecycle coordination patterns include:
- **Parent drives children**: A parent resource starts/stops children explicitly (e.g., via hooks or orchestration code).
- **Parent mirrors a child**: A composite or wrapper resource reflects the lifecycle or readiness of one of its children.
- **Inherit from children (ad hoc)**: Some resources choose to inherit or mirror lifecycle from children. This is not standardized and is not inferred from `IResourceWithParent`.

Visual relationships:
- Affect **only the dashboard layout**.
- **Do not affect lifecycle** — the resources are independent operationally.
- Improve **clarity** by logically grouping related components.
Lifecycle coordination is typically implemented by propagating events to child resources (see [Well-Known Lifecycle Events](#well-known-lifecycle-events)).

> **Example:**
> A Redis database container and a Redis Commander admin UI container can be grouped visually, even though they start independently.
Example: A logging sidecar that is started and stopped together with a main application container can be implemented by the parent explicitly coordinating the child. This behavior is authored by the integration and not implied by `IResourceWithParent`.

---

### Manual Relationships — No Inference

Aspire **does not infer** parent-child relationships automatically based on names, dependencies, or network links.
You must **explicitly declare** either:
Aspire does not infer parent-child relationships automatically based on names, dependencies, or network links.
You must explicitly declare relationships using either:

- `IResourceWithParent` (for lifecycle and visual nesting)
- or `.WithParentRelationship()` (for visual nesting only)
- **`IResourceWithParent`** (for structural containment and visual nesting), or
- **`.WithParentRelationship()`** (for visual nesting only)

This explicitness ensures developers have full control over resource containment and presentation.
This explicitness ensures developers have full control over resource containment, presentation, and any optional lifecycle behavior.

---

### Real-World Examples

| Scenario | Parent | Child |
|----------|--------|-------|
| Database server with owned database | Database server | Database (child's lifetime owned by the parent server; implemented by the integration) |
| Main application container with logging sidecar | App container | Fluentd container |
| Database with admin dashboard | Database container | Admin UI container |
| Microservice with associated health monitor | API container | Health probe container |

Note: In the "database server with owned database" scenario, the lifetime of the database is owned by the parent database server. This is achieved via resource-specific lifecycle coordination and is not implied by IResourceWithParent alone.

---

## Values and References
Expand Down