Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ public void halt() throws ConnectorTaskException, InterruptedException {
if (scheduler != null) {
try {
scheduler.interrupt(job.getKey());
// Release the scheduler as stop() does, without waiting for the interrupted job.
// StdSchedulerFactory keeps a running scheduler under the channel ID, so the next
// deploy would get this one back with the poll job still stored and fail with
// ObjectAlreadyExistsException. See OpenIntegrationEngine/engine#571.
scheduler.shutdown(false);
} catch (Exception e) {
throw new ConnectorTaskException(e);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// SPDX-License-Identifier: MPL-2.0
// SPDX-FileCopyrightText: Open Integration Engine Contributors

package com.mirth.connect.donkey.server.channel;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import org.junit.Test;

import com.mirth.connect.donkey.server.event.EventDispatcher;
import com.mirth.connect.donkey.test.util.TestPollConnectorProperties;

/**
* A halted poll connector must release its Quartz scheduler, so the channel can be deployed and
* started again on the same engine. See OpenIntegrationEngine/engine#571.
*/
public class PollConnectorHaltTest {

private static class NoopPollConnector extends PollConnector {
@Override
public void onDeploy() {}

@Override
public void onUndeploy() {}

@Override
public void onStart() {}

@Override
public void onStop() {}

@Override
public void onHalt() {}

@Override
protected void poll() {}

@Override
public void handleRecoveredResponse(DispatchResult dispatchResult) {}
}

private static PollConnector connector(String channelId) {
Channel channel = mock(Channel.class);
when(channel.getEventDispatcher()).thenReturn(mock(EventDispatcher.class));

PollConnector connector = new NoopPollConnector();
connector.setChannelId(channelId);
connector.setChannel(channel);
connector.setConnectorProperties(new TestPollConnectorProperties());
return connector;
}

/** Before the fix, the second start threw ObjectAlreadyExistsException for the poll job. */
@Test
public void startAfterHalt_onANewConnectorForTheSameChannel() throws Exception {
String channelId = "poll-halt-redeploy-test";

PollConnector first = connector(channelId);
first.start();
first.halt();

PollConnector second = connector(channelId);
second.start();
second.stop();
}

/** Halt then Start on the same connector, as the Dashboard does without undeploying. */
@Test
public void startAfterHalt_onTheSameConnector() throws Exception {
PollConnector connector = connector("poll-halt-restart-test");
connector.start();
connector.halt();

connector.start();
connector.stop();
}

/** Stop already released the scheduler; it keeps working. */
@Test
public void startAfterStop_onANewConnectorForTheSameChannel() throws Exception {
String channelId = "poll-stop-redeploy-test";

PollConnector first = connector(channelId);
first.start();
first.stop();

PollConnector second = connector(channelId);
second.start();
second.stop();
}
}