Skip to content

Commit

Permalink
Use new idempotent API for mazerunner command fetch
Browse files Browse the repository at this point in the history
  • Loading branch information
kstenerud committed Dec 28, 2023
1 parent 28519c3 commit 91d1926
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 18 deletions.
54 changes: 42 additions & 12 deletions features/fixtures/ios/Fixture/CommandReaderThread.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import os
class CommandReaderThread: Thread {
var fixtureConfig: FixtureConfig
var commandReceiver: CommandReceiver
var lastCommandID: String = ""

init(fixtureConfig: FixtureConfig, commandReceiver: CommandReceiver) {
self.fixtureConfig = fixtureConfig
Expand All @@ -29,29 +30,53 @@ class CommandReaderThread: Thread {
}
}

func receiveNextCommand() {
let fetchTask = CommandFetchTask(url: fixtureConfig.commandURL)
func newStartedFetchTask() -> CommandFetchTask {
let fetchTask = CommandFetchTask(url: fixtureConfig.commandURL, afterCommandID: lastCommandID)
fetchTask.start()
return fetchTask
}

func receiveNextCommand() {
let maxWaitTime = 5.0
let pollingInterval = 1.0

var fetchTask = newStartedFetchTask()
let startTime = Date()

while true {
Thread.sleep(forTimeInterval: pollingInterval)
switch fetchTask.state {
case CommandFetchState.success:
commandReceiver.receiveCommand(command: fetchTask.command!)
logDebug("Command fetch: Request succeeded")
let command = fetchTask.command!
lastCommandID = command.uuid
commandReceiver.receiveCommand(command: command)
return
case CommandFetchState.fetching:
logDebug("Command fetch server hasn't responded yet, waiting 1 second more...")
Thread.sleep(forTimeInterval: 1)
let duration = Date() - startTime
if duration < maxWaitTime {
logDebug("Command fetch: Server hasn't responded in \(duration)s (max \(maxWaitTime)). Waiting \(pollingInterval)s more...")
} else {
fetchTask.cancel()
logInfo("Command fetch: Server hasn't responded in \(duration)s (max \(maxWaitTime)). Trying again...")
fetchTask = newStartedFetchTask()
}
break
case CommandFetchState.failed:
logInfo("Command fetch request failed. Trying again...")
Thread.sleep(forTimeInterval: 1)
fetchTask.start()
logInfo("Command fetch: Request failed. Trying again...")
fetchTask = newStartedFetchTask()
break
}
}
}
}

extension Date {
static func - (lhs: Date, rhs: Date) -> TimeInterval {
return lhs.timeIntervalSinceReferenceDate - rhs.timeIntervalSinceReferenceDate
}
}

enum CommandFetchState {
case failed, fetching, success
}
Expand All @@ -60,16 +85,21 @@ class CommandFetchTask {
var url: URL
var state = CommandFetchState.failed
var command: MazeRunnerCommand?
var task: URLSessionTask?

init(url: URL, afterCommandID: String) {
self.url = URL(string: "\(url.absoluteString)?after=\(afterCommandID)")!
}

init(url: URL) {
self.url = url
func cancel() {
task?.cancel()
}

func start() {
logInfo("Fetching next command from \(url)")
state = CommandFetchState.fetching
let request = URLRequest(url: url)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
task = URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
Expand All @@ -88,6 +118,6 @@ class CommandFetchTask {
logError("Failed to fetch command: HTTP Request to \(String(describing: self.url)) failed: \(error)")
}
}
task.resume()
task?.resume()
}
}
5 changes: 4 additions & 1 deletion features/fixtures/ios/Fixture/MazeRunnerCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,19 @@ import Foundation
class MazeRunnerCommand: Codable {
let message: String
let action: String
let uuid: String
let args: Array<String>

init(action: String, args: Array<String>, message: String) {
init(uuid: String, action: String, args: Array<String>, message: String) {
self.uuid = uuid
self.message = message
self.action = action
self.args = args
}

required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.uuid = try container.decodeIfPresent(String.self, forKey: .uuid) ?? ""
self.message = try container.decodeIfPresent(String.self, forKey: .message) ?? ""
self.action = try container.decodeIfPresent(String.self, forKey: .action) ?? ""
self.args = try container.decodeIfPresent(Array<String>.self, forKey: .args) ?? []
Expand Down
13 changes: 8 additions & 5 deletions features/fixtures/ios/Scenarios/Scenario.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,17 @@ class Scenario: NSObject {
}

func isMazeRunnerAdministrationURL(url: URL) -> Bool {
switch url {
case fixtureConfig.tracesURL, fixtureConfig.commandURL, fixtureConfig.metricsURL:
if url.absoluteString.hasPrefix(fixtureConfig.tracesURL.absoluteString) ||
url.absoluteString.hasPrefix(fixtureConfig.commandURL.absoluteString) ||
url.absoluteString.hasPrefix(fixtureConfig.metricsURL.absoluteString) {
return true
case fixtureConfig.reflectURL:
}

if url.absoluteString.hasPrefix(fixtureConfig.reflectURL.absoluteString) {
return false // reflectURL is fair game!
default:
return false
}

return false
}

func reportMeasurements() {
Expand Down

0 comments on commit 91d1926

Please sign in to comment.