|
13 | 13 | //===----------------------------------------------------------------------===//
|
14 | 14 |
|
15 | 15 | import CoreMetrics
|
| 16 | +import Dispatch |
16 | 17 | import NIO
|
17 | 18 | import NIOConcurrencyHelpers
|
18 | 19 |
|
@@ -245,6 +246,15 @@ private final class Client {
|
245 | 246 |
|
246 | 247 | private let isShutdown = NIOAtomic<Bool>.makeAtomic(value: false)
|
247 | 248 |
|
| 249 | + private var state = State.disconnected |
| 250 | + private let lock = Lock() |
| 251 | + |
| 252 | + private enum State { |
| 253 | + case disconnected |
| 254 | + case connecting(EventLoopFuture<Void>) |
| 255 | + case connected(Channel) |
| 256 | + } |
| 257 | + |
248 | 258 | init(eventLoopGroupProvider: StatsdClient.EventLoopGroupProvider, address: SocketAddress) {
|
249 | 259 | self.eventLoopGroupProvider = eventLoopGroupProvider
|
250 | 260 | switch self.eventLoopGroupProvider {
|
@@ -273,8 +283,37 @@ private final class Client {
|
273 | 283 | }
|
274 | 284 |
|
275 | 285 | func emit(_ metric: Metric) -> EventLoopFuture<Void> {
|
276 |
| - return self.connect().flatMap { channel in |
277 |
| - channel.writeAndFlush(metric) |
| 286 | + self.lock.lock() |
| 287 | + switch self.state { |
| 288 | + case .disconnected: |
| 289 | + let promise = self.eventLoopGroup.next().makePromise(of: Void.self) |
| 290 | + self.state = .connecting(promise.futureResult) |
| 291 | + self.lock.unlock() |
| 292 | + self.connect().flatMap { channel -> EventLoopFuture<Void> in |
| 293 | + self.lock.withLock { |
| 294 | + guard case .connecting = self.state else { |
| 295 | + preconditionFailure("invalid state \(self.state)") |
| 296 | + } |
| 297 | + self.state = .connected(channel) |
| 298 | + } |
| 299 | + return self.emit(metric) |
| 300 | + }.cascade(to: promise) |
| 301 | + return promise.futureResult |
| 302 | + case .connecting(let future): |
| 303 | + let future = future.flatMap { |
| 304 | + self.emit(metric) |
| 305 | + } |
| 306 | + self.state = .connecting(future) |
| 307 | + self.lock.unlock() |
| 308 | + return future |
| 309 | + case .connected(let channel): |
| 310 | + guard channel.isActive else { |
| 311 | + self.state = .disconnected |
| 312 | + self.lock.unlock() |
| 313 | + return self.emit(metric) |
| 314 | + } |
| 315 | + self.lock.unlock() |
| 316 | + return channel.writeAndFlush(metric) |
278 | 317 | }
|
279 | 318 | }
|
280 | 319 |
|
|
0 commit comments