From da1c38a2a73c194a76495f640759cbd248c27215 Mon Sep 17 00:00:00 2001 From: Erik Doernenburg Date: Mon, 8 Apr 2024 19:40:11 +0200 Subject: [PATCH] Made requests work in parallel again. --- .../Source/Server Monitor/ServerMonitor.swift | 26 ++++++++++++++----- .../ServerMonitorIntegrationTests.swift | 26 +++++++++++++++++++ 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/CCMenu/Source/Server Monitor/ServerMonitor.swift b/CCMenu/Source/Server Monitor/ServerMonitor.swift index 3fc8af8..03eb911 100644 --- a/CCMenu/Source/Server Monitor/ServerMonitor.swift +++ b/CCMenu/Source/Server Monitor/ServerMonitor.swift @@ -60,16 +60,22 @@ class ServerMonitor { } private func updateStatus(pipelines: [Pipeline]) async { - for g in Dictionary(grouping: pipelines.filter({ $0.feed.type == .cctray }), by: { $0.feed.url }).values { - await updateCCTrayPipelines(group: g) - } - for p in pipelines.filter({ $0.feed.type == .github }) { - await updateGitHubPipeline(pipeline: p) + await withTaskGroup(of: Void.self) { taskGroup in + self.updatePipelines_CCTray(pipelines.filter({ $0.feed.type == .cctray }), taskGroup: &taskGroup) + self.updatePipelines_GitHub(pipelines.filter({ $0.feed.type == .github }), taskGroup: &taskGroup) + await taskGroup.waitForAll() } } - // TODO: Consider moving the following methods to the reader and an abstract reader base class + // TODO: Consider moving the following methods to the reader, with a protocol and base class + // TODO: Consider adding a limit to the number of parallel requests (see https://stackoverflow.com/questions/70976323/) + private func updatePipelines_CCTray(_ pipelines: [Pipeline], taskGroup: inout TaskGroup) { + for pg in Dictionary(grouping: pipelines, by: { $0.feed.url }).values { + taskGroup.addTask { await self.updateCCTrayPipelines(group: pg) } + } + } + private func updateCCTrayPipelines(group: [Pipeline]) async { var group = group guard let pipeline = group.first else { return } @@ -83,6 +89,13 @@ class ServerMonitor { await reader.updatePipelineStatus() reader.pipelines.forEach({ model.update(pipeline: $0) }) } + + + private func updatePipelines_GitHub(_ pipelines: [Pipeline], taskGroup: inout TaskGroup) { + for p in pipelines { + taskGroup.addTask { await self.updateGitHubPipeline(pipeline: p) } + } + } private func updateGitHubPipeline(pipeline: Pipeline) async { var pipeline = pipeline @@ -100,6 +113,7 @@ class ServerMonitor { model.update(pipeline: reader.pipeline) } + private func pipelineIsRemote(_ p: Pipeline) -> Bool { if let url = URL(string: p.feed.url), url.host() != "localhost" { return true diff --git a/CCMenuIntegrationTests/ServerMonitorIntegrationTests.swift b/CCMenuIntegrationTests/ServerMonitorIntegrationTests.swift index bcbd04d..5bda2e2 100644 --- a/CCMenuIntegrationTests/ServerMonitorIntegrationTests.swift +++ b/CCMenuIntegrationTests/ServerMonitorIntegrationTests.swift @@ -82,6 +82,32 @@ final class ServerMonitorIntegrationTests: XCTestCase { XCTAssertEqual("build.123", model.pipelines.first(where: { $0.name == "other-project" })?.status.lastBuild?.label) XCTAssertEqual(1, requestCounter) } + + func testMakesRequestsForCCTrayFeedsInParallel() async throws { + var processingFirstRequest = false + var sawProcessingFirstRequestInSecondRequest = false + webapp.router.get("/1/cctray.xml") { _ in + processingFirstRequest = true + // TODO: It's crude to sleep but we can't use DispatchSemaphore in async method + Thread.sleep(forTimeInterval: 1) + processingFirstRequest = false + return "" + } + webapp.router.get("/2/cctray.xml") { _ in + sawProcessingFirstRequestInSecondRequest = processingFirstRequest + return "" + } + + let model = PipelineModel() + model.add(pipeline: Pipeline(name: "connectfour-1", feed: Pipeline.Feed(type: .cctray, url: "http://localhost:8086/1/cctray.xml", name: "connectfour"))) + model.add(pipeline: Pipeline(name: "connectfour-2", feed: Pipeline.Feed(type: .cctray, url: "http://localhost:8086/2/cctray.xml", name: "connectfour"))) + + let monitor = await ServerMonitor(model: model) + await monitor.updateStatusIfPollTimeHasBeenReached() + + XCTAssertTrue(sawProcessingFirstRequestInSecondRequest) + } + func testDoesntPollWhenGitHubPipelineIsPaused() async throws { var requestCounter = 0