Skip to content
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

Startup order isn't preserved when using modules #1152

Open
Philio opened this issue Feb 7, 2024 · 2 comments
Open

Startup order isn't preserved when using modules #1152

Philio opened this issue Feb 7, 2024 · 2 comments

Comments

@Philio
Copy link

Philio commented Feb 7, 2024

Describe the bug
I've bundled some commonly used dependencies in modules for convenience, for example db initialisation and web server start up. In one of my web services I implemented them as follows (with the intention that the data migration function runs before the web server starts):

	fx.New(
		...
		service.DatastoreModule,  // Configures and connects to Google cloud datastore
		fx.Invoke(runMigrations), // Runs data migrations
		service.ServerModule,     // Configures routing and starts web server
	).Run()

But on startup the web server always starts first and the web server's OnStart hook is called first:

[Fx] INVOKE             ***/service.startServer() from module "server"
...
[Fx] INVOKE             main.runMigrations()
...
[Fx] HOOK OnStart               ***/service.startServer.func1() executing (caller: ***/service.startServer)
[Fx] HOOK OnStart               ***/service.startServer.func1() called by ***/service.startServer ran successfully in 3.48µs
[Fx] HOOK OnStart               ***/service.newDatastoreClient.func1() executing (caller: ***/service.newDatastoreClient)
[country] 2024/02/07 02:36:50.404627 Starting HTTP server on 0.0.0.0:8080
[Fx] HOOK OnStart               ***/service.newDatastoreClient.func1() called by ***/service.newDatastoreClient ran successfully in 435.478µs
[Fx] HOOK OnStart               main.runMigrations.func1() executing (caller: main.runMigrations)
[Fx] HOOK OnStart               main.runMigrations.func1() called by main.runMigrations ran successfully in 1.45µs

However if I wrap the migrations in a module as well:

	fx.New(
		...
		service.DatastoreModule,
		migrationsModule,
		service.ServerModule,
	).Run()

Now it works as expected:

[Fx] INVOKE             main.runMigrations() from module "migrations"
...
[Fx] INVOKE             github.com/boxes-ltd/service-common/service.startServer() from module "server"
...
[Fx] HOOK OnStart               ***/service.newDatastoreClient.func1() executing (caller: ***/service.newDatastoreClient)
[Fx] HOOK OnStart               ***/service.newDatastoreClient.func1() called by ***/service.newDatastoreClient ran successfully in 406.037µs
[Fx] HOOK OnStart               main.runMigrations.func1() executing (caller: main.runMigrations)
[Fx] HOOK OnStart               main.runMigrations.func1() called by main.runMigrations ran successfully in 1.42µs
[Fx] HOOK OnStart               ***/service.startServer.func1() executing (caller: ***/service.startServer)
[Fx] HOOK OnStart               ***/service.startServer.func1() called by ***/service.startServer ran successfully in 780ns

Since documentation states:

Startup hooks, also referred to as OnStart hooks. These run in the order they were appended.

It seems like this is a bug, I couldn't see anything that states that a module takes precedence.

To Reproduce

Add an invoke function before a module that contains an invoke function.

Expected behavior

I would have expected functions to be called in the order they are defined.

Additional context
Add any other context about the problem here.

@dismantl
Copy link

dismantl commented Feb 8, 2024

I wonder if #918 is related?

@JacobOaks
Copy link
Contributor

Hey @Philio, Invoke run order is specified differently than Hook run order. This is a documented behavior. See fx.Invoke documentation.

Invokes registered in Modules are run before the ones registered at the scope of the parent. Invokes within the same Module are run in the order they were provided.

Based on this and the code you're showing, things seem to be running in the expected order.

As a more general comment, if you want to enforce that certain things are run before others without having to worry about the order in which you list them, specify explicit dependencies between them appropriately. I.e., have the migration functionality produce a result that your Invoke in ServerModule depends on.

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

No branches or pull requests

3 participants