Skip to content

Instantly share code, notes, and snippets.

@davidfowl
Last active July 12, 2025 23:22
Show Gist options
  • Save davidfowl/b408af870d4b5b54a28bf18bffa127e1 to your computer and use it in GitHub Desktop.
Save davidfowl/b408af870d4b5b54a28bf18bffa127e1 to your computer and use it in GitHub Desktop.
Aspire Resource Model: Concepts, Design, and Authoring Guidance
@asimmon
Copy link

asimmon commented May 14, 2025

Example: Cross-Context Communication

  • Missing grafana and keycloak resource declaration (or was it omitted on purpose?)

Annotations:

  • WithAnnotation(): maybe mention behavior to append (default) or replace an existing one
  • Retrieving annotations can also be done from the resource.Annotations property, like resource.Annotations.OfType<ResourceSnapshotAnnotation>() when there can be many of a given annotation type

IDistributedApplicationLifecycleHook is only shown in an example. I built many features on top of this primitive - maybe it deserves its own section.

  • Methods are blocking
  • Most of the time I keep background tasks in fields instead of starting non-observed tasks (like _ = DoSomethingAsync(ct)) - mostly for logging and ensuring background tasks work well until the end of the execution (final await in DisposeAsync).
  • Custom resources implementing IResourceWithWaitSupport may depend on other resources, so call notificationService.WaitForDependenciesAsync(resource, ct) before doing any custom orchestration

Common interfaces:

  • Mention IResourceWithWaitSupport

@davidfowl
Copy link
Author

WithAnnotation(): maybe mention behavior to append (default) or replace an existing one

Good call out.

Retrieving annotations can also be done from the resource.Annotations property, like resource.Annotations.OfType() when there can be many of a given annotation type

πŸ‘

Custom resources implementing IResourceWithWaitSupport may depend on other resources, so call notificationService.WaitForDependenciesAsync(resource, ct) before doing any custom orchestration

πŸ‘

IDistributedApplicationLifecycleHook is only shown in an example. I built many features on top of this primitive - maybe it deserves its own section.

We want people to switch to eventing, I think we need a couple more version then we'll recommend people use the other API as that will drive the custom resource lifecycle (and will solve lots of the problems we have manually building resources today).

@oising
Copy link

oising commented Jun 3, 2025

When a resource implements the IResourceWithParent interface, it declares true containment β€” meaning its lifecycle is controlled by its parent:

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.

I find this really confusing as a resource author. It implies that IResourceWithParent imparts direct and automatic control of child resources, when the reality is very different. Resource authors decide which methods comprise startup calls, and also they choose lifecycle hooks and wire up eventing to call these things. How exactly does Aspire enforce these semantics?

@oising
Copy link

oising commented Jun 3, 2025

There could be an analyzer that validates this -- example, if we say that "start" methods should be annotated with [EntryPoint] or [Startup], then a basic analyzer could ensure that these methods are not being called inside inappropriate eventing callbacks. Even then, this won't cover all scenarios. Something feels "off."

@davidfowl
Copy link
Author

I think we will change this assumption. This really only applies to specific resources...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment