Skip to content

Commit 02ab651

Browse files
authored
Add RequestID to generate unique Identifier for each request (#326)
* Add RequestID to generate unique Identifier for each request This will also generate unique identifiers across multiple instances of a Humminbird application * Don't bother with leading zeros for high value in request id * Don't need to store high in RequestID as it is the same for all ids * Don't keep rebuilding high string
1 parent 8b6590a commit 02ab651

File tree

3 files changed

+76
-10
lines changed

3 files changed

+76
-10
lines changed

Sources/Hummingbird/Server/Request.swift

+2-5
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the Hummingbird server framework project
44
//
5-
// Copyright (c) 2021-2022 the Hummingbird authors
5+
// Copyright (c) 2021-2023 the Hummingbird authors
66
// Licensed under Apache License v2.0
77
//
88
// See LICENSE.txt for license information
@@ -12,7 +12,6 @@
1212
//
1313
//===----------------------------------------------------------------------===//
1414

15-
import Atomics
1615
import HummingbirdCore
1716
import Logging
1817
import NIOConcurrencyHelpers
@@ -106,7 +105,7 @@ public struct HBRequest: Sendable, HBSendableExtensible {
106105
context: context
107106
)
108107
self.body = body
109-
self.logger = application.logger.with(metadataKey: "hb_id", value: .stringConvertible(Self.globalRequestID.loadThenWrappingIncrement(by: 1, ordering: .relaxed)))
108+
self.logger = application.logger.with(metadataKey: "hb_id", value: .stringConvertible(RequestID()))
110109
self.extensions = .init()
111110
}
112111

@@ -215,8 +214,6 @@ public struct HBRequest: Sendable, HBSendableExtensible {
215214
}
216215

217216
private var _internal: _Internal
218-
219-
private static let globalRequestID = ManagedAtomic(0)
220217
}
221218

222219
extension Logger {
+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Hummingbird server framework project
4+
//
5+
// Copyright (c) 2023 the Hummingbird authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See hummingbird/CONTRIBUTORS.txt for the list of Hummingbird authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
import Atomics
16+
17+
/// Generate Unique ID for each request
18+
struct RequestID: CustomStringConvertible {
19+
let low: UInt64
20+
21+
init() {
22+
self.low = Self.globalRequestID.loadThenWrappingIncrement(by: 1, ordering: .relaxed)
23+
}
24+
25+
var description: String {
26+
Self.high + self.formatAsHexWithLeadingZeros(self.low)
27+
}
28+
29+
func formatAsHexWithLeadingZeros(_ value: UInt64) -> String {
30+
let string = String(value, radix: 16)
31+
if string.count < 16 {
32+
return String(repeating: "0", count: 16 - string.count) + string
33+
} else {
34+
return string
35+
}
36+
}
37+
38+
private static let high = String(UInt64.random(in: .min ... .max), radix: 16)
39+
private static let globalRequestID = ManagedAtomic<UInt64>(UInt64.random(in: .min ... .max))
40+
}

Tests/HummingbirdTests/RouterTests.swift

+34-5
Original file line numberDiff line numberDiff line change
@@ -331,25 +331,54 @@ final class RouterTests: XCTestCase {
331331
}
332332
}
333333

334-
/// Test we have a request id and that it increments with each request
334+
/// Test we have a request id and that it is unique for each request
335335
func testRequestId() throws {
336336
let app = HBApplication(testing: .embedded)
337337
app.router.get("id") { $0.id }
338338
try app.XCTStart()
339339
defer { app.XCTStop() }
340340

341-
let idString = try app.XCTExecute(uri: "/id", method: .GET) { response -> String in
341+
let id = try app.XCTExecute(uri: "/id", method: .GET) { response -> String in
342342
let body = try XCTUnwrap(response.body)
343343
return String(buffer: body)
344344
}
345-
let id = try XCTUnwrap(Int(idString))
346345
try app.XCTExecute(uri: "/id", method: .GET) { response in
347346
let body = try XCTUnwrap(response.body)
348-
let id2 = Int(String(buffer: body))
349-
XCTAssertEqual(id2, id + 1)
347+
let id2 = String(buffer: body)
348+
XCTAssertNotEqual(id2, id)
350349
}
351350
}
352351

352+
/// Test we have a request id and that it is unique for each request even across instances
353+
/// of running applications
354+
func testRequestIdAcrossInstances() throws {
355+
let id: String?
356+
do {
357+
let app = HBApplication(testing: .embedded)
358+
app.router.get("id") { $0.id }
359+
try app.XCTStart()
360+
defer { app.XCTStop() }
361+
362+
id = try app.XCTExecute(uri: "/id", method: .GET) { response -> String in
363+
let body = try XCTUnwrap(response.body)
364+
return String(buffer: body)
365+
}
366+
}
367+
let id2: String?
368+
do {
369+
let app = HBApplication(testing: .embedded)
370+
app.router.get("id") { $0.id }
371+
try app.XCTStart()
372+
defer { app.XCTStop() }
373+
374+
id2 = try app.XCTExecute(uri: "/id", method: .GET) { response -> String in
375+
let body = try XCTUnwrap(response.body)
376+
return String(buffer: body)
377+
}
378+
}
379+
XCTAssertNotEqual(id, id2)
380+
}
381+
353382
// Test redirect response
354383
func testRedirect() throws {
355384
let app = HBApplication(testing: .embedded)

0 commit comments

Comments
 (0)