mlevkov opened a new pull request, #4064:
URL: https://github.com/apache/iggy/pull/4064

   Closes #4062.
   
   ## The leak
   
   `SourceManager::start_connector` takes a fresh `plugin_id`, calls 
`init_source`, and records that id on `SourceDetails` only after the handler 
tasks are spawned. In between, the instance exists inside the plugin and 
nothing outside it knows the id: `stop_connector` closes whatever 
`details.info.id` holds, which is still the previous instance. 
`setup_source_producer` returning early through `?` therefore stranded the new 
one for the life of the process. `source::init` already cleaned up on the 
identical failure, which is the asymmetry @hubcio pointed at.
   
   For a plugin whose open only allocates, the orphan is wasted memory. For one 
that takes a process-global resource it is a live fault: a shared listener 
stays bound and answering into a queue nothing drains, and every retried 
restart then fails on the identity the orphan never released.
   
   ## A guard, not a cleanup branch
   
   This deviates from the fix in the review, which was to mirror 
`source::init`'s error arm at the call site, so it is worth saying why rather 
than leaving it to be found.
   
   The window is defined by the two statements that open the instance and 
record its id, not by which call between them happens to be fallible today. A 
cleanup branch is correct only for the one `?` that exists now, and silently 
wrong for the next one somebody adds. `SourceInstanceGuard` is armed at 
`init_source` and disarmed once the id is recorded, so every path out of that 
window closes the instance, including a panic.
   
   It also made the behaviour testable. `Container<SourceApi>` only comes from 
`dlopen`, so `start_connector` cannot be exercised in a unit test at all, while 
a guard holding the bare `extern "C" fn` can be driven directly.
   
   The close-and-report itself is now one function shared with `source::init`, 
so the two sites cannot drift. `source::init` keeps its existing control flow; 
only the duplicated body moved.
   
   No `cleanup_sender` on this path: `spawn_source_handler` is what registers 
the sender, and it has not run yet.
   
   ## Tests
   
   Three, each mutation-checked, each mutant confirmed to compile first:
   
   - an armed guard closes, and closes *its own* id, since closing another 
would leave this instance open and tear down a live one
   - a disarmed guard does not close, or a source that just started 
successfully would be torn down
   - a refused close (`-1`, the code the SDK returns for an unknown id) is 
reported and not propagated, because unwinding out of `drop` would be worse 
than the leak it is cleaning up after
   
   Each test owns its stub and statics rather than sharing a pair, which would 
have made two of them race in the same process.
   
   ## What is not covered, and why
   
   **The guard's placement in `start_connector` has no test.** I verified that 
rather than assuming it: disarming the guard immediately after construction 
restores the original leak, compiles, and the suite still passes.
   
   Reaching that path needs a real `Container`, so it cannot be a unit test, 
and the only route into `start_connector` is `POST /sources/{key}/restart`. 
Making `setup_source_producer` fail there means either a config the local 
provider will serve on restart but not at boot, which today works only because 
of the version selection in #3848 and would break when that is fixed, or 
stopping the broker mid-test. Both couple this regression test to something 
unrelated to it, so I left it out rather than write a test that fails for the 
wrong reason later. Happy to add either if you would rather have the coverage 
than the independence.
   
   `source::init`'s cleanup remains covered only by `error_isolation.rs` 
asserting the connector reports `Error`, which it did before this change too.
   
   ## Verification
   
   `cargo fmt`, `cargo sort --no-format`, clippy at both feature sets, rustdoc 
under `-D warnings`, 198 unit tests in `iggy-connectors`, and `stdout_sink` + 
`random_source` still build.
   


-- 
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