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
17 changes: 11 additions & 6 deletions forge/ee/routes/teamBroker/3rdPartyBroker.js
Original file line number Diff line number Diff line change
Expand Up @@ -447,10 +447,18 @@ module.exports = async function (app) {
} else if (agent?.state === 'starting') {
// Another start is already launching the agent: starting is a no-op
reply.status(200).send({})
} else if (agent && agent.state !== 'running') {
await app.containers.sendBrokerAgentCommand(agent, 'start')
} else if (agent) {
// The agent is up. The stored 'running' state doesn't tell us whether
// it's actually collecting, so ask the agent. Only send start when it
// isn't connected (stopped via the API or after the 24h auto-shutdown),
// since start fully tears the agent down and reconnects it, which would
// take a healthy agent offline and drop in-flight messages.
const status = await app.containers.getBrokerAgentState(agent)
if (!status?.connected) {
await app.containers.sendBrokerAgentCommand(agent, 'start')
}
reply.status(200).send({})
} else if (!agent) {
} else {
// Stays 'starting' until the driver has launched the agent, so a suspend
// arriving meanwhile is refused rather than missing a process it can't stop yet
const agent = await app.db.models.TeamBrokerAgent.create({
Expand All @@ -467,9 +475,6 @@ module.exports = async function (app) {
agent.state = 'running'
await agent.save()
reply.status(200).send({})
} else {
// Agent already running: starting is a no-op
reply.status(200).send({})
}
} else {
if (request.broker.state === 'running') {
Expand Down
47 changes: 40 additions & 7 deletions test/unit/forge/ee/routes/teamBroker/3rdPartyBroker_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -781,14 +781,47 @@ describe('3rd Party Broker API', function () {
await app.db.models.TeamBrokerAgent.destroy({ where: { TeamId: app.team.id } })
})

it('start replies when the team-broker agent is already running', async function () {
it('start resumes a team-broker agent that is up but no longer collecting', async function () {
// After a stop or the 24h auto-shutdown the agent stays recorded as running
// but is no longer connected, so switching the toggle on must re-issue the
// start command to resume collection.
const agent = await app.db.models.TeamBrokerAgent.create({ state: 'running', TeamId: app.team.id })
const getBrokerAgentState = sinon.stub(app.containers, 'getBrokerAgentState').resolves({ connected: false, error: null })
const sendBrokerAgentCommand = sinon.stub(app.containers, 'sendBrokerAgentCommand').resolves()
try {
const response = await app.inject({
method: 'POST',
url: `/api/v1/teams/${app.team.hashid}/brokers/team-broker/start`,
cookies: { sid: TestObjects.tokens.bob }
})
response.statusCode.should.equal(200)
sendBrokerAgentCommand.calledOnce.should.be.true()
sendBrokerAgentCommand.firstCall.args[0].should.have.property('id', agent.id)
sendBrokerAgentCommand.firstCall.args[1].should.equal('start')
} finally {
sendBrokerAgentCommand.restore()
getBrokerAgentState.restore()
}
})

it('start leaves a team-broker agent that is already collecting alone', async function () {
// A connected agent is already collecting; sending it start would tear the
// broker down and reconnect, so this must stay a no-op.
await app.db.models.TeamBrokerAgent.create({ state: 'running', TeamId: app.team.id })
const response = await app.inject({
method: 'POST',
url: `/api/v1/teams/${app.team.hashid}/brokers/team-broker/start`,
cookies: { sid: TestObjects.tokens.bob }
})
response.statusCode.should.equal(200)
const getBrokerAgentState = sinon.stub(app.containers, 'getBrokerAgentState').resolves({ connected: true, error: null })
const sendBrokerAgentCommand = sinon.stub(app.containers, 'sendBrokerAgentCommand').resolves()
try {
const response = await app.inject({
method: 'POST',
url: `/api/v1/teams/${app.team.hashid}/brokers/team-broker/start`,
cookies: { sid: TestObjects.tokens.bob }
})
response.statusCode.should.equal(200)
sendBrokerAgentCommand.called.should.be.false()
} finally {
sendBrokerAgentCommand.restore()
getBrokerAgentState.restore()
}
})

it('stop replies when the team-broker agent is not running', async function () {
Expand Down
Loading