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

context: AppIfConfigured returns error; consider not-yet-provisioned modules #6292

Merged
merged 3 commits into from May 20, 2024

Conversation

francislavoie
Copy link
Member

@francislavoie francislavoie commented May 2, 2024

Context https://caddy.community/t/app-not-available-during-provisioning/23678

The problem is that our two existing methods ctx.App(name) and ctx.AppIfConfigured(name) don't properly cover the case where a module might want to get a configured module instance, because AppIfConfigured() could be called before the configured app is actually provisioned, and App() could provision an empty app even though it wasn't configured.

So to plug that gap, I propose we add an ctx.AppStrict(name) method which is the same as ctx.App(name) except that it throws an error early if the app wasn't configured. If it was already loaded then it just returns that, if configured it just loads it and returns it. The method's name is open for discussion if anyone can think of something better.

I also realized that a couple of our usages of AppIfConfigured() were error prone due to provisioning order not being guaranteed, so I switched them to use this new method.

There's still one remaining case where we use AppIfConfigured() which is in the TLS app's cleanup, we check if the next config (which must have been fully started/provisioned before cleanup of the first config happens) also has a TLS app, and if so pass stuff along. That's to say AppIfConfigured() still has a purpose for those kinds of handoff scenarios.

@francislavoie francislavoie added the feature ⚙️ New feature or request label May 2, 2024
@francislavoie francislavoie added this to the v2.8.0 milestone May 2, 2024
@francislavoie
Copy link
Member Author

Actually, @mholt arguably 0e2c7e1 broke the intended semantics of AppIfConfigured(). I don't think it was correct to change how it worked without also providing a way to get an app without loading an empty one. I think the AppStrict() API is probably a better name for it in the end.

@mholt
Copy link
Member

mholt commented May 3, 2024

We talked about that change though. Instantiating an app when it wasn't loaded was problematic.

@mholt
Copy link
Member

mholt commented May 3, 2024

Ok, discussed on Slack, and quoting your summary here:

Both were and you changed it from problem A to problem B without leaving a way to do A, and AppStrict() is a new way to solve A:

A = need to get the configured app even if load order caused it to not yet be loaded, but don't want a default app if not configured
B = need to get the configured app but don't want to load if it wasn't, only valid to be called after provision when it's guaranteed everything is loaded already
C = (existing App() function) need to get an app even if not configured because it's a hard-dependency

context.go Outdated
Comment on lines 475 to 481
// Since this method does not return the app if it has not been
// provisioned, this could be misleading if the provisioning order
// caused the app to not be provisioned yet. This could return
// nil even if the app is configured, but not yet provisioned.
// In that case, the caller should probably use AppStrict() instead
// to ensure the app is provisioned, and no app will be instantiated
// if it is not configured.
Copy link
Member

Choose a reason for hiding this comment

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

So the more I read this, the more I think we need to just fix this: if the app has been configured, load and provision it if needed. Otherwise, don't. This method is called AppIfConfigured not AppIfProvisionedAlready...

What do you think if we try to do that?

Copy link
Member

Choose a reason for hiding this comment

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

Assuming you had a particular need when you changed it in 0e2c7e1, are those semantics not needed anymore?

Copy link
Member

Choose a reason for hiding this comment

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

I don't think either change is quite right though...

The earlier version would provision an app that maybe shouldn't be provisioned (I forgot about the nondeterminstic order). The change makes it never provision the app, but also disregards the loading order.

AppIfConfigured should provision the app if, but ONLY if, it will be provisioned.

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't think I follow. So what do you think should be done? Just rename AppStrict to AppIfConfigured (and drop the current one & functionality)?

Why did the difference matter for the cert cache commit again? Can you give an example of when it would have been wrong?

Copy link
Member

Choose a reason for hiding this comment

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

I'm a dummy, AppStrict() already does exactly what I'm describing, lol.

So yeah, let's replace AppIfConfigured with AppStrict. This does add an error return to the signature but we had it originally and I don't think there's anyone using this yet? (maybe 1 or 2? I apologize if that breaks anyone, but it's a very very easy patch, and I think this is an important fix).

@mohammed90
Copy link
Member

A = need to get the configured app even if load order caused it to not yet be loaded, but don't want a default app if not configured
B = need to get the configured app but don't want to load if it wasn't, only valid to be called after provision when it's guaranteed everything is loaded already
C = (existing App() function) need to get an app even if not configured because it's a hard-dependency

This summary is pretty neat. It'd be great if we can have it documented this way somewhere.

@mholt mholt changed the title context: Add new AppStrict() method to avoid instantiating empty apps context: AppIfConfigured returns error; consider not-yet-provisioned modules May 20, 2024
@mholt mholt merged commit a6a45ff into master May 20, 2024
23 checks passed
@mholt mholt deleted the ctx-app-strict branch May 20, 2024 17:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature ⚙️ New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants