git.iko.soy/parseable-macos
on master help sign in
Fix 3 bugs: stale sort task, cache invalidation after stream ops, and auth fallback
3eb694ciko
ParseableViewer/Services/ParseableClient.swift+11
@@ -230,11 +230,16 @@ final class ParseableClient: Sendable {
230 func createStream(name: String) async throws {
230 func createStream(name: String) async throws {
231 let encoded = try Self.encodePathComponent(name)
231 let encoded = try Self.encodePathComponent(name)
232 _ = try await performRequest(method: "PUT", path: "/api/v1/logstream/\(encoded)")
232 _ = try await performRequest(method: "PUT", path: "/api/v1/logstream/\(encoded)")
233+ // Recreating a same-named stream must not serve a previous stream's
234+ // cached schema/stats/info (cached for 60s), so drop the cache.
235+ await cache.invalidate()
233 }
236 }
234
237
235 func deleteStream(name: String) async throws {
238 func deleteStream(name: String) async throws {
236 let encoded = try Self.encodePathComponent(name)
239 let encoded = try Self.encodePathComponent(name)
237 _ = try await performRequest(method: "DELETE", path: "/api/v1/logstream/\(encoded)")
240 _ = try await performRequest(method: "DELETE", path: "/api/v1/logstream/\(encoded)")
241+ // Invalidate so a later same-named stream doesn't see stale schema/stats/info.
242+ await cache.invalidate()
238 }
243 }
239
244
240 func getStreamSchema(stream: String) async throws -> StreamSchema {
245 func getStreamSchema(stream: String) async throws -> StreamSchema {
@@ -343,6 +348,12 @@ final class ParseableClient: Sendable {
343 }
348 }
344 return config
349 return config
345 } catch let newEndpointError {
350 } catch let newEndpointError {
351+ // An auth failure won't be fixed by hitting the legacy endpoint (it
352+ // would just 401 again), so surface it immediately rather than
353+ // delaying the re-auth prompt behind a second failing round-trip.
354+ if case ParseableError.unauthorized = newEndpointError {
355+ throw newEndpointError
356+ }
346 do {
357 do {
347 return try await legacyAlerts()
358 return try await legacyAlerts()
348 } catch {
359 } catch {
ParseableViewer/Views/LiveTailView.swift+5−1
@@ -306,13 +306,17 @@ struct LiveTailView: View {
306 entries.map { ($0.id, extractSeverity(from: $0.record, severityColumns: sevCols)) },
306 entries.map { ($0.id, extractSeverity(from: $0.record, severityColumns: sevCols)) },
307 uniquingKeysWith: { first, _ in first }
307 uniquingKeysWith: { first, _ in first }
308 )
308 )
309+ // Cancel any pending sort task before either path: when the sort is
310+ // cleared (guard below), a previously-scheduled task could otherwise
311+ // wake after its 150ms delay and overwrite the unsorted result with
312+ // stale sorted entries.
313+ liveTailSortTask?.cancel()
309 guard let col = sortColumn else {
314 guard let col = sortColumn else {
310 cachedSorted = entries
315 cachedSorted = entries
311 severityColumnSet = sevCols
316 severityColumnSet = sevCols
312 severityByID = severityMap
317 severityByID = severityMap
313 return
318 return
314 }
319 }
315− liveTailSortTask?.cancel()
316 let asc = sortAscending
320 let asc = sortAscending
317 liveTailSortTask = Task {
321 liveTailSortTask = Task {
318 try? await Task.sleep(for: .milliseconds(150))
322 try? await Task.sleep(for: .milliseconds(150))