7
7
import com .google .common .annotations .VisibleForTesting ;
8
8
import com .google .common .net .HttpHeaders ;
9
9
import io .dropwizard .auth .Auth ;
10
- import io .lettuce .core .RedisException ;
11
10
import io .micrometer .core .instrument .Metrics ;
12
11
import io .micrometer .core .instrument .Tags ;
13
12
import io .micrometer .core .instrument .Timer ;
81
80
import org .whispersystems .textsecuregcm .storage .DeviceCapability ;
82
81
import org .whispersystems .textsecuregcm .storage .DeviceSpec ;
83
82
import org .whispersystems .textsecuregcm .storage .LinkDeviceTokenAlreadyUsedException ;
83
+ import org .whispersystems .textsecuregcm .storage .PersistentTimer ;
84
84
import org .whispersystems .textsecuregcm .util .DeviceCapabilityAdapter ;
85
85
import org .whispersystems .textsecuregcm .util .EnumMapUtil ;
86
86
import org .whispersystems .textsecuregcm .util .ExceptionUtils ;
@@ -100,6 +100,7 @@ public class DeviceController {
100
100
private final AccountsManager accounts ;
101
101
private final ClientPublicKeysManager clientPublicKeysManager ;
102
102
private final RateLimiters rateLimiters ;
103
+ private final PersistentTimer persistentTimer ;
103
104
private final Map <String , Integer > maxDeviceConfiguration ;
104
105
105
106
private final EnumMap <ClientPlatform , AtomicInteger > linkedDeviceListenersByPlatform ;
@@ -108,9 +109,11 @@ public class DeviceController {
108
109
private static final String LINKED_DEVICE_LISTENER_GAUGE_NAME =
109
110
MetricsUtil .name (DeviceController .class , "linkedDeviceListeners" );
110
111
112
+ private static final String WAIT_FOR_LINKED_DEVICE_TIMER_NAMESPACE = "wait_for_linked_device" ;
111
113
private static final String WAIT_FOR_LINKED_DEVICE_TIMER_NAME =
112
114
MetricsUtil .name (DeviceController .class , "waitForLinkedDeviceDuration" );
113
115
116
+ private static final String WAIT_FOR_TRANSFER_ARCHIVE_TIMER_NAMESPACE = "wait_for_transfer_archive" ;
114
117
private static final String WAIT_FOR_TRANSFER_ARCHIVE_TIMER_NAME =
115
118
MetricsUtil .name (DeviceController .class , "waitForTransferArchiveDuration" );
116
119
@@ -124,11 +127,13 @@ public class DeviceController {
124
127
public DeviceController (final AccountsManager accounts ,
125
128
final ClientPublicKeysManager clientPublicKeysManager ,
126
129
final RateLimiters rateLimiters ,
130
+ final PersistentTimer persistentTimer ,
127
131
final Map <String , Integer > maxDeviceConfiguration ) {
128
132
129
133
this .accounts = accounts ;
130
134
this .clientPublicKeysManager = clientPublicKeysManager ;
131
135
this .rateLimiters = rateLimiters ;
136
+ this .persistentTimer = persistentTimer ;
132
137
this .maxDeviceConfiguration = maxDeviceConfiguration ;
133
138
134
139
linkedDeviceListenersByPlatform =
@@ -366,32 +371,30 @@ The amount of time (in seconds) to wait for a response. If the expected device i
366
371
@ HeaderParam (HttpHeaders .USER_AGENT ) String userAgent ) {
367
372
final AtomicInteger linkedDeviceListenerCounter = getCounterForLinkedDeviceListeners (userAgent );
368
373
linkedDeviceListenerCounter .incrementAndGet ();
369
- final Timer .Sample sample = Timer .start ();
370
374
371
375
return rateLimiters .getWaitForLinkedDeviceLimiter ()
372
376
.validateAsync (authenticatedDevice .getAccount ().getIdentifier (IdentityType .ACI ))
373
- .thenCompose (ignored -> accounts .waitForNewLinkedDevice (
374
- authenticatedDevice .getAccount ().getUuid (),
375
- authenticatedDevice .getAuthenticatedDevice (),
376
- tokenIdentifier ,
377
- Duration .ofSeconds (timeoutSeconds )))
378
- .thenApply (maybeDeviceInfo -> maybeDeviceInfo
379
- .map (deviceInfo -> Response .status (Response .Status .OK ).entity (deviceInfo ).build ())
380
- .orElseGet (() -> Response .status (Response .Status .NO_CONTENT ).build ()))
381
- .exceptionally (ExceptionUtils .exceptionallyHandler (IllegalArgumentException .class ,
382
- e -> Response .status (Response .Status .BAD_REQUEST ).build ()))
383
- .whenComplete ((response , throwable ) -> {
384
- linkedDeviceListenerCounter .decrementAndGet ();
385
-
386
- if (response != null ) {
387
- sample .stop (Timer .builder (WAIT_FOR_LINKED_DEVICE_TIMER_NAME )
388
- .publishPercentileHistogram (true )
389
- .tags (Tags .of (UserAgentTagUtil .getPlatformTag (userAgent ),
390
- io .micrometer .core .instrument .Tag .of ("deviceFound" ,
391
- String .valueOf (response .getStatus () == Response .Status .OK .getStatusCode ()))))
392
- .register (Metrics .globalRegistry ));
393
- }
394
- });
377
+ .thenCompose (ignored -> persistentTimer .start (WAIT_FOR_LINKED_DEVICE_TIMER_NAMESPACE , tokenIdentifier ))
378
+ .thenCompose (sample -> accounts .waitForNewLinkedDevice (
379
+ authenticatedDevice .getAccount ().getUuid (),
380
+ authenticatedDevice .getAuthenticatedDevice (),
381
+ tokenIdentifier ,
382
+ Duration .ofSeconds (timeoutSeconds ))
383
+ .thenApply (maybeDeviceInfo -> maybeDeviceInfo
384
+ .map (deviceInfo -> Response .status (Response .Status .OK ).entity (deviceInfo ).build ())
385
+ .orElseGet (() -> Response .status (Response .Status .NO_CONTENT ).build ()))
386
+ .exceptionally (ExceptionUtils .exceptionallyHandler (IllegalArgumentException .class ,
387
+ e -> Response .status (Response .Status .BAD_REQUEST ).build ()))
388
+ .whenComplete ((response , throwable ) -> {
389
+ linkedDeviceListenerCounter .decrementAndGet ();
390
+
391
+ if (response != null && response .getStatus () == Response .Status .OK .getStatusCode ()) {
392
+ sample .stop (Timer .builder (WAIT_FOR_LINKED_DEVICE_TIMER_NAME )
393
+ .publishPercentileHistogram (true )
394
+ .tags (Tags .of (UserAgentTagUtil .getPlatformTag (userAgent )))
395
+ .register (Metrics .globalRegistry ));
396
+ }
397
+ }));
395
398
}
396
399
397
400
private AtomicInteger getCounterForLinkedDeviceListeners (final String userAgent ) {
@@ -529,7 +532,8 @@ The amount of time (in seconds) to wait for a response. If a transfer archive fo
529
532
public CompletionStage <Void > recordTransferArchiveUploaded (@ ReadOnly @ Auth final AuthenticatedDevice authenticatedDevice ,
530
533
@ NotNull @ Valid final TransferArchiveUploadedRequest transferArchiveUploadedRequest ) {
531
534
532
- return rateLimiters .getUploadTransferArchiveLimiter ().validateAsync (authenticatedDevice .getAccount ().getIdentifier (IdentityType .ACI ))
535
+ return rateLimiters .getUploadTransferArchiveLimiter ()
536
+ .validateAsync (authenticatedDevice .getAccount ().getIdentifier (IdentityType .ACI ))
533
537
.thenCompose (ignored -> accounts .recordTransferArchiveUpload (authenticatedDevice .getAccount (),
534
538
transferArchiveUploadedRequest .destinationDeviceId (),
535
539
Instant .ofEpochMilli (transferArchiveUploadedRequest .destinationDeviceCreated ()),
@@ -568,30 +572,25 @@ The amount of time (in seconds) to wait for a response. If a transfer archive fo
568
572
569
573
@ HeaderParam (HttpHeaders .USER_AGENT ) @ Nullable String userAgent ) {
570
574
571
- final Timer .Sample sample = Timer .start ();
572
575
573
576
final String rateLimiterKey = authenticatedDevice .getAccount ().getIdentifier (IdentityType .ACI ) +
574
577
":" + authenticatedDevice .getAuthenticatedDevice ().getId ();
575
578
576
579
return rateLimiters .getWaitForTransferArchiveLimiter ().validateAsync (rateLimiterKey )
577
- .thenCompose (ignored -> accounts .waitForTransferArchive (authenticatedDevice .getAccount (),
578
- authenticatedDevice .getAuthenticatedDevice (),
579
- Duration .ofSeconds (timeoutSeconds )))
580
- .thenApply (maybeTransferArchive -> maybeTransferArchive
581
- .map (transferArchive -> Response .status (Response .Status .OK ).entity (transferArchive ).build ())
582
- .orElseGet (() -> Response .status (Response .Status .NO_CONTENT ).build ()))
583
- .whenComplete ((response , throwable ) -> {
584
- if (response == null ) {
585
- return ;
586
- }
587
- sample .stop (Timer .builder (WAIT_FOR_TRANSFER_ARCHIVE_TIMER_NAME )
588
- .publishPercentileHistogram (true )
589
- .tags (Tags .of (
590
- UserAgentTagUtil .getPlatformTag (userAgent ),
591
- io .micrometer .core .instrument .Tag .of (
592
- "archiveUploaded" ,
593
- String .valueOf (response .getStatus () == Response .Status .OK .getStatusCode ()))))
594
- .register (Metrics .globalRegistry ));
595
- });
580
+ .thenCompose (ignored -> persistentTimer .start (WAIT_FOR_TRANSFER_ARCHIVE_TIMER_NAMESPACE , rateLimiterKey ))
581
+ .thenCompose (sample -> accounts .waitForTransferArchive (authenticatedDevice .getAccount (),
582
+ authenticatedDevice .getAuthenticatedDevice (),
583
+ Duration .ofSeconds (timeoutSeconds ))
584
+ .thenApply (maybeTransferArchive -> maybeTransferArchive
585
+ .map (transferArchive -> Response .status (Response .Status .OK ).entity (transferArchive ).build ())
586
+ .orElseGet (() -> Response .status (Response .Status .NO_CONTENT ).build ()))
587
+ .whenComplete ((response , throwable ) -> {
588
+ if (response != null && response .getStatus () == Response .Status .OK .getStatusCode ()) {
589
+ sample .stop (Timer .builder (WAIT_FOR_TRANSFER_ARCHIVE_TIMER_NAME )
590
+ .publishPercentileHistogram (true )
591
+ .tags (Tags .of (UserAgentTagUtil .getPlatformTag (userAgent )))
592
+ .register (Metrics .globalRegistry ));
593
+ }
594
+ }));
596
595
}
597
596
}
0 commit comments