diff --git a/docs/specs/appmodel.md b/docs/specs/appmodel.md index 9a808f35fdf..0e76e3d7664 100644 --- a/docs/specs/appmodel.md +++ b/docs/specs/appmodel.md @@ -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) @@ -387,50 +386,46 @@ 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. --- @@ -438,10 +433,13 @@ This explicitness ensures developers have full control over resource containment | 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