gnodet commented on issue #13827:
URL: https://github.com/apache/maven/issues/13827#issuecomment-6639331548

   The root cause here is that `MojoExecutionScope` has always been 
`ThreadLocal`-based (since MNG-5530 in 2012), and that is intentional: when 
running with `-T N`, multiple mojo executions run concurrently on different 
threads, and the `ThreadLocal` isolates their scoped state.
   
   ## Maven 3.9.x
   
   Option 2 (documentation + guidance) is the right answer for 3.x. The 
workaround in apache/maven-site-plugin#1350 — routing document rendering back 
to the mojo thread via a queue — is the correct pattern. Plugins that spawn 
worker threads must not let those threads look up `@MojoExecutionScoped` 
components, because there is no scope state on those threads. This should be 
documented clearly.
   
   ## Maven 4
   
   The situation is cleaner by design:
   
   **A v4 plugin** gets a fresh `Injector` per mojo execution (created in 
`DefaultMavenPluginManager`), with `Session`, `Project`, `MojoExecution`, and 
`Log` bound directly as plain instances via `bindInstance`. There is no 
`ThreadLocal` involved at all. A mojo simply declares:
   
   ```java
   @Inject Session session;
   @Inject Project project;
   @Inject MojoExecution mojoExecution;
   ```
   
   ...and gets the right instances for that execution automatically. If the 
mojo spawns worker threads, it passes those objects explicitly as parameters — 
no scope, no magic.
   
   v4 mojos are thread-safe by design: each execution gets a fresh mojo 
instance with its own injector, so no mojo state is ever shared between 
concurrent executions. This is what makes v4 mojos safe to run in parallel 
builds without locking.
   
   If a plugin needs to share state across multiple mojo invocations (e.g. an 
`initialize` mojo and a `verify` mojo sharing computed data), it can inject a 
`@SessionScoped` or `@Singleton` bean — those are resolved from the shared 
container, not the per-execution local injector, so they survive across 
executions for the duration of the build. Those shared beans are the only place 
where explicit thread-safety is required.
   
   **A core extension** (`.mvn/extensions.xml`) lives in the shared container 
and can use `@SessionScoped` for session-lifetime components. The existing 
`@MojoExecutionScoped` (v3 annotation, Plexus/Sisu/Guice path) still works for 
extensions that need per-execution lifecycle — but even then, the `ThreadLocal` 
constraint applies: the scope is only valid on the mojo thread.
   
   ## On `org.apache.maven.api.di.MojoExecutionScoped` (the v4 annotation)
   
   This annotation exists in `maven-api-di` but is unfinished and unusable: the 
Guice binding in `MojoExecutionScopeModule` is commented out, there is no proxy 
path for injecting it into a wider scope (unlike `@SessionScoped` which creates 
a JDK proxy transparently), and no production code in Maven itself uses it. We 
should remove it from the v4 API to avoid confusion — v4 plugins do not need it 
(they get execution context via direct injection), and extensions that need 
scoped components should use the established v3 annotation or `@SessionScoped`.
   
   ## On Option 1 (context propagation API)
   
   Not justified. It would work around a design problem rather than fixing it. 
Plugins that need concurrent work should pass context explicitly, not rely on 
transparent scope propagation across threads.
   
   ## Long-term for `site:run`
   
   Migrating `maven-site-plugin` to the v4 API is the right fix. Doxia parsers 
would receive `Session` and `Project` via direct injection or explicit 
parameter passing — no scoped lookups, no `ThreadLocal`, no thread issues.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to