Skip to content

Release the poll scheduler on halt so the channel can redeploy (fixes #571) - #574

Open
iacsha wants to merge 2 commits into
OpenIntegrationEngine:mainfrom
iacsha:fix/571-halted-poller-redeploy
Open

iacsha wants to merge 2 commits into
OpenIntegrationEngine:mainfrom
iacsha:fix/571-halted-poller-redeploy

Conversation

@iacsha

@iacsha iacsha commented Nov 12, 2026

Copy link
Copy Markdown
Contributor

Fixes #571.

Problem

After a polling channel is halted and undeployed, deploying it again on the same engine returns HTTP 500:

Caused by: com.mirth.connect.donkey.server.ConnectorTaskException: org.quartz.ObjectAlreadyExistsException: Unable to store Job : '<channelId>.PollConnector<channelId>', because one already exists with this identification.
	at com.mirth.connect.donkey.server.channel.PollConnector.start(PollConnector.java:44)

PollConnectorJobHandler creates the Quartz scheduler with StdSchedulerFactory and sets org.quartz.scheduler.instanceName to the channel ID. The factory keeps a running scheduler in its SchedulerRepository under that name until it is shut down. PollConnector.stop() shuts it down, but halt() only calls scheduler.interrupt(job.getKey()). So after a halt, the next deploy's factory.getScheduler() gets the old scheduler back with the poll job still stored, and scheduleJob fails.

Fix

halt() now also calls scheduler.shutdown(false) after interrupting the job. false means it doesn't wait for the interrupted job to finish, so a halt stays immediate. stop() is unchanged.

Tests

New PollConnectorHaltTest:

  • A minimal PollConnector is started and halted, then a new connector for the same channel ID is started.
  • The same sequence with stop instead of halt, as a control.

The halt case fails without this change with the exact exception above. With it, both pass. :donkey:test and :server:test are green.

I haven't rerun the REST repro from the issue against a built engine. The unit test exercises the same start → halt → start path through the same StdSchedulerFactory repository.

…penIntegrationEngine#571)

PollConnector.stop() shuts its Quartz scheduler down, but halt() only
interrupted the running job. StdSchedulerFactory keeps a running
scheduler under its instance name, which is the channel ID, so the next
deploy of the same channel got the old scheduler back with the poll job
still stored, and start() failed with ObjectAlreadyExistsException.

halt() now also calls scheduler.shutdown(false), which does not wait for
the interrupted job. Adds PollConnectorHaltTest; the halt case fails
with the reported exception without this change.

Signed-off-by: iacsha <122627209+iacsha@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown

Test Results

  143 files  +1    143 suites  +1   4m 12s ⏱️ +58s
  939 tests +2    939 ✅ +2  0 💤 ±0  0 ❌ ±0 
1 101 runs  +2  1 095 ✅ +2  6 💤 ±0  0 ❌ ±0 

Results for commit a1d21f9. ± Comparison against base commit cd802ef.

pacmano1
pacmano1 previously approved these changes Nov 12, 2026

@pacmano1 pacmano1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ran the issue's REST repro on engines built from main and from this branch, on Derby. Main: deploying after Halt returns 500 with the ObjectAlreadyExistsException. This branch: deploys and polls again. Same for the File Reader and the Database Reader, and for Halt then Start without undeploying, which also failed on main. Halting in the middle of a long poll works too. A poll that ignores the interrupt keeps running, but it delivers nothing once the channel is redeployed.

Optional: a third test calling start() on the same connector after halt() would cover the Halt then Start path.

Co-authored with Claude Code.

…e#571)

Signed-off-by: iacsha <122627209+iacsha@users.noreply.github.com>
@iacsha

iacsha commented Nov 13, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for testing it end to end. Added the third test in d41fcba: startAfterHalt_onTheSameConnector calls start(), halt(), then start() and stop() on one connector. It fails on main with the same ObjectAlreadyExistsException and passes on this branch.

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.

A halted polling channel cannot be deployed again on the same engine

2 participants