Skip to content

Conversation

@afscrome
Copy link
Contributor

@afscrome afscrome commented Nov 23, 2025

Closes #942 (Fixing that issue wasn't a specific goal of this Pr, but it just so happens to fix it).

Update Dac Pack resources to better follow aspire resource conventions

  • Rework Sql Project resource to let Aspire handle the waiting, rather than handling it via a custom implementation
  • Use Standard Resource states
    • Pending / Not Started --> Let aspire handle it
    • Publishing --> Running
    • Exceptions during the publish process now become Exited with an exit code, rather than FailedtoStart
  • Add icon for database projects
  • Add resource properties for SqlPackage and project based SqlPackage- in particular the source which will show up on the dashboard, but also start/end times
image - Tweaked test to fail fast if a resource entered an unexpected terminal state, rather than hanging until the timeout.

In particular this involves removing any custom publishing of the ResourceReadyEvent as this explicitly called out as something that should not be done:

Important: Developers should not manually publish the ResourceReadyEvent. Aspire manages the transition to the ready state based on the presence and outcome of health checks. Manually firing this event can interfere with the orchestration logic.
https://github.com/dotnet/aspire/blob/main/docs/specs/appmodel.md#resource-health

The key to getting aspire to do the waiting for us is to publish the BeforeStart event to kick off our process, and wait for that to process. See the talking clock example at https://github.com/dotnet/aspire/blob/main/docs/specs/appmodel.md#example-custom-resource---talking-clock for more details.

This did involve making sure to not wait on the target database to avoid a deadlock. Previously WithReference effectively did

target.OnResourceReady(...)
builder.WaitFor(target);

But this is a circular dependency. WaitFor doesn't unblock until all ResourceReady events have completed. But the OnResourceReady handler needed to block until all the dacpac's dependencies were healthy. For dacpac's purposes, the WaitFor(target) was unnecessary.

PR Checklist

  • Created a feature/dev branch in your fork (vs. submitting directly from a commit on main)
  • Based off latest main branch of toolkit
  • PR doesn't include merge commits (always rebase on top of our main, if needed)
  • Contains NO breaking changes
  • Every new API (including internal ones) has full XML docs
  • Code follows all style conventions

The change of resource states is be a breaking change if any consumers are doing any custom waiting on those states. Some (but not all) of these state changes are required to let aspire handle the Waiting for us, but I felt it was easier to bring everything inline, rather than just some.

Other information

I'm not entirely sure if OnResourceReady is the right place to execute the dacpacs, as it blocks the database from going healthy until t's complete. Whilst I'm sure this is often the behaviour you want, I'm not sure it's always what is wanted. (WithExplicitStart is a clear example of this, but I can imagine some other users may not want to be blocking). But this is where execution was being done prior to now, so things are no worse with this Pr than they were before.

- Rework Sql Project resource to let Aspire handle the waiting, rather than handling it via a custom implementation

- Refactor Publishing to not `Exited` with an exit code rather than `FailedToStart` if the publishing process started, but then failed.

- Use Standard Resource states
  - Pending / Not Started --> Let aspire handle it
  - Publishing --> Running
  - Exceptions during the publish process now become `Exited`

- Add icon for database projects

- Add resource properties for SqlPackage projects - in particular the state which will show up on the dashboard.

In particular this involves removing any custom publishing of the `ResourceReadyEvent` as this explicitly called out as something that should not be done:

> Important: Developers should not manually publish the ResourceReadyEvent. Aspire manages the transition to the ready state based on the presence and outcome of health checks. Manually firing this event can interfere with the orchestration logic.
https://github.com/dotnet/aspire/blob/main/docs/specs/appmodel.md#resource-health

The key to getting aspire to do the waiting for us is to use `OnInitialize` to kick off our process.  See the talking clock example at https://github.com/dotnet/aspire/blob/main/docs/specs/appmodel.md#example-custom-resource---talking-clock for more details.

One thing I'm not entirely sure of is whether or not a `SqlProject` resource was intended to deploy multiple bacpacks from a signle resource.  The current implemention look.  If this is not intended, we can get rid of the `DacpackTargetAnnotation` and inline those properties on the resource itself.  If this was intended, we can make `DacpackTargetAnnotation` public.
@ErikEJ
Copy link
Contributor

ErikEJ commented Nov 23, 2025

Looks like a test time out...

What do you mean by your question re deploy multiple?

Do you mean deploy multiple .dacpacs against the same database? I think that would be a valid scenario.

@afscrome
Copy link
Contributor Author

Sorry, was in a bit of a rush before going out for the day, let me look at the tests

For the multiple scenario, what should happen with the following:

.WithDacpac("foo.bacpac")
.WithDacpac("baz.bacpac")

Should this mean one SqlProject resource deploys multiple dacpacs, or should the later call replace the first call, with the expectation being each dacpac needs it's own SqlPackage resource?

@afscrome afscrome marked this pull request as ready for review November 23, 2025 22:32
@afscrome
Copy link
Contributor Author

afscrome commented Nov 23, 2025

Fixed the tests (although unrelated SurrealDb tests are failing). Also realise I misunderstood the resource lifecycle on my first pass, so my previous question was irrelevant. I've updated the Pr description to describe the Pr with the latest changes.

Copy link
Member

@aaronpowell aaronpowell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm ultimately not familiar enough with this section of the code base, so I'll leave it to @ErikEJ and @jmezach to approve/merge if they are comfortable with it.

@ErikEJ
Copy link
Contributor

ErikEJ commented Nov 24, 2025

@afscrome Great work, I will pull the PR and do some smoke testing - but LGTM

@aaronpowell
Copy link
Member

@ErikEJ @jmezach if you can tackle this over the next day or so, we can ship it in 13 (which I'd like to get out shortly)

@ErikEJ
Copy link
Contributor

ErikEJ commented Nov 24, 2025

@afscrome @aaronpowell @jmezach I have smoke tested, works just as expected, and with much better state indications during launch than before.

@jmezach
Copy link
Contributor

jmezach commented Nov 24, 2025

I also ran a couple of tests and seems to work as advertised now. Thanks @afscrome for this!

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Wait ignored when a SqlProject waits for another SqlProject

4 participants