Skip to content

Commit aeb4def

Browse files
authored
Libraries should save state if a completion block is requested (#5147)
* Libraries should save state if a completion block is requested Currently, the onComplete block of sendXEvent:onComplete: is invoked when the event bytes are written to disk. However, if the app crashes before a lifecycle event occurs (trigger GDTCORStorage to serialize to disk), that event if effectively lost because the metadata has all been lost. This change triggers the saving of state of GDTCORStorage and prioritizers (if they implement it) if an onComplete block has been given. * Remove flaky check * Update GDTCORStorage.m
1 parent 19f6183 commit aeb4def

File tree

10 files changed

+53
-33
lines changed

10 files changed

+53
-33
lines changed

GoogleDataTransport/GDTCORLibrary/GDTCORStorage.m

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,17 @@ - (instancetype)init {
5959
}
6060

6161
- (void)storeEvent:(GDTCOREvent *)event
62-
onComplete:(void (^)(BOOL wasWritten, NSError *error))completion {
62+
onComplete:(void (^_Nullable)(BOOL wasWritten, NSError *error))completion {
6363
GDTCORLogDebug("Saving event: %@", event);
6464
if (event == nil) {
6565
GDTCORLogDebug("%@", @"The event was nil, so it was not saved.");
6666
return;
6767
}
68+
BOOL hadOriginalCompletion = completion != nil;
6869
if (!completion) {
6970
completion = ^(BOOL wasWritten, NSError *error) {
71+
GDTCORLogDebug(@"event %@ stored. success:%@ error:%@", event, wasWritten ? @"YES" : @"NO",
72+
error);
7073
};
7174
}
7275

@@ -102,17 +105,26 @@ - (void)storeEvent:(GDTCOREvent *)event
102105
// Add event to tracking collections.
103106
[self addEventToTrackingCollections:event];
104107

105-
// Have the prioritizer prioritize the event.
108+
// Have the prioritizer prioritize the event and save state if there was an onComplete block.
106109
[prioritizer prioritizeEvent:event];
110+
if (hadOriginalCompletion && [prioritizer respondsToSelector:@selector(saveState)]) {
111+
[prioritizer saveState];
112+
GDTCORLogDebug(@"Prioritizer %@ has saved state due to an event's onComplete block.",
113+
prioritizer);
114+
}
107115

108116
// Check the QoS, if it's high priority, notify the target that it has a high priority event.
109117
if (event.qosTier == GDTCOREventQoSFast) {
110118
[self.uploadCoordinator forceUploadForTarget:target];
111119
}
112120

113-
// Write state to disk if we're in the background.
114-
if ([[GDTCORApplication sharedApplication] isRunningInBackground]) {
115-
GDTCORLogDebug("%@", @"Saving storage state because the app is running in the background");
121+
// Write state to disk if there was an onComplete block or if we're in the background.
122+
if (hadOriginalCompletion || [[GDTCORApplication sharedApplication] isRunningInBackground]) {
123+
if (hadOriginalCompletion) {
124+
GDTCORLogDebug("%@", @"Saving storage state because a completion block was passed.");
125+
} else {
126+
GDTCORLogDebug("%@", @"Saving storage state because the app is running in the background");
127+
}
116128
NSError *error;
117129
GDTCOREncodeArchive(self, [GDTCORStorage archivePath], &error);
118130
if (error) {

GoogleDataTransport/GDTCORLibrary/GDTCORTransformer.m

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,9 @@ - (instancetype)init {
4848

4949
- (void)transformEvent:(GDTCOREvent *)event
5050
withTransformers:(NSArray<id<GDTCOREventTransformer>> *)transformers
51-
onComplete:(nonnull void (^)(BOOL wasWritten, NSError *error))completion {
51+
onComplete:(void (^_Nullable)(BOOL wasWritten, NSError *error))completion {
5252
GDTCORAssert(event, @"You can't write a nil event");
53+
BOOL hadOriginalCompletion = completion != nil;
5354
if (!completion) {
5455
completion = ^(BOOL wasWritten, NSError *_Nullable error) {
5556
};
@@ -79,7 +80,8 @@ - (void)transformEvent:(GDTCOREvent *)event
7980
return;
8081
}
8182
}
82-
[self.storageInstance storeEvent:transformedEvent onComplete:completion];
83+
[self.storageInstance storeEvent:transformedEvent
84+
onComplete:hadOriginalCompletion ? completion : nil];
8385

8486
// The work is done, cancel the background task if it's valid.
8587
[[GDTCORApplication sharedApplication] endBackgroundTask:bgID];

GoogleDataTransport/GDTCORLibrary/GDTCORTransport.m

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -49,37 +49,21 @@ - (nullable instancetype)initWithMappingID:(NSString *)mappingID
4949
- (void)sendTelemetryEvent:(GDTCOREvent *)event
5050
onComplete:(void (^)(BOOL wasWritten, NSError *_Nullable error))completion {
5151
event.qosTier = GDTCOREventQoSTelemetry;
52-
[self sendEvent:event
53-
onComplete:^(BOOL wasWritten, NSError *error) {
54-
GDTCORLogDebug("Telemetry event sent: %@", event);
55-
if (completion) {
56-
completion(wasWritten, nil);
57-
}
58-
}];
52+
[self sendEvent:event onComplete:completion];
5953
}
6054

6155
- (void)sendDataEvent:(GDTCOREvent *)event
6256
onComplete:(void (^)(BOOL wasWritten, NSError *_Nullable error))completion {
6357
GDTCORAssert(event.qosTier != GDTCOREventQoSTelemetry, @"Use -sendTelemetryEvent, please.");
64-
[self sendEvent:event
65-
onComplete:^(BOOL wasWritten, NSError *error) {
66-
GDTCORLogDebug("Data event sent: %@", event);
67-
if (completion) {
68-
completion(wasWritten, nil);
69-
}
70-
}];
58+
[self sendEvent:event onComplete:completion];
7159
}
7260

7361
- (void)sendTelemetryEvent:(GDTCOREvent *)event {
74-
[self sendTelemetryEvent:event
75-
onComplete:^(BOOL wasWritten, NSError *_Nullable error){
76-
}];
62+
[self sendTelemetryEvent:event onComplete:nil];
7763
}
7864

7965
- (void)sendDataEvent:(GDTCOREvent *)event {
80-
[self sendDataEvent:event
81-
onComplete:^(BOOL wasWritten, NSError *_Nullable error){
82-
}];
66+
[self sendDataEvent:event onComplete:nil];
8367
}
8468

8569
- (GDTCOREvent *)eventForTransport {
@@ -94,7 +78,7 @@ - (GDTCOREvent *)eventForTransport {
9478
* @param completion A block that will be called when the event has been written or dropped.
9579
*/
9680
- (void)sendEvent:(GDTCOREvent *)event
97-
onComplete:(void (^)(BOOL wasWritten, NSError *error))completion {
81+
onComplete:(void (^_Nullable)(BOOL wasWritten, NSError *error))completion {
9882
// TODO: Determine if sending an event before registration is allowed.
9983
GDTCORAssert(event, @"You can't send a nil event");
10084
GDTCOREvent *copiedEvent = [event copy];

GoogleDataTransport/GDTCORLibrary/Private/GDTCORStorage.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ NS_ASSUME_NONNULL_BEGIN
3838
* @param completion A block to run when an event was written to disk or dropped.
3939
*/
4040
- (void)storeEvent:(GDTCOREvent *)event
41-
onComplete:(void (^)(BOOL wasWritten, NSError *error))completion;
41+
onComplete:(void (^_Nullable)(BOOL wasWritten, NSError *error))completion;
4242

4343
/** Removes a set of events from storage specified by their hash.
4444
*

GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransformer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ NS_ASSUME_NONNULL_BEGIN
4949
*/
5050
- (void)transformEvent:(GDTCOREvent *)event
5151
withTransformers:(nullable NSArray<id<GDTCOREventTransformer>> *)transformers
52-
onComplete:(void (^)(BOOL wasWritten, NSError *_Nullable error))completion;
52+
onComplete:(void (^_Nullable)(BOOL wasWritten, NSError *_Nullable error))completion;
5353

5454
@end
5555

GoogleDataTransport/GDTCORLibrary/Public/GDTCORPrioritizer.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@ typedef NS_OPTIONS(NSInteger, GDTCORUploadConditions) {
6969
- (GDTCORUploadPackage *)uploadPackageWithTarget:(GDTCORTarget)target
7070
conditions:(GDTCORUploadConditions)conditions;
7171

72+
@optional
73+
74+
/** Saves the state of the prioritizer. */
75+
- (void)saveState;
76+
7277
@end
7378

7479
NS_ASSUME_NONNULL_END

GoogleDataTransport/GDTCORLibrary/Public/GDTCORTransport.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ NS_ASSUME_NONNULL_BEGIN
4949
* @param completion A block that will be called when the event has been written or dropped.
5050
*/
5151
- (void)sendTelemetryEvent:(GDTCOREvent *)event
52-
onComplete:(void (^)(BOOL wasWritten, NSError *_Nullable error))completion;
52+
onComplete:(void (^_Nullable)(BOOL wasWritten, NSError *_Nullable error))completion;
5353

5454
/** Copies and sends an internal telemetry event. Events sent using this API are lower in priority,
5555
* and sometimes won't be sent on their own.
@@ -69,7 +69,7 @@ NS_ASSUME_NONNULL_BEGIN
6969
* @param completion A block that will be called when the event has been written or dropped.
7070
*/
7171
- (void)sendDataEvent:(GDTCOREvent *)event
72-
onComplete:(void (^)(BOOL wasWritten, NSError *_Nullable error))completion;
72+
onComplete:(void (^_Nullable)(BOOL wasWritten, NSError *_Nullable error))completion;
7373

7474
/** Copies and sends an SDK service data event. Events send using this API are higher in priority,
7575
* and will cause a network request at some point in the relative near future.

GoogleDataTransport/GDTCORTests/Integration/Helpers/GDTCORIntegrationTestPrioritizer.m

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ - (GDTCORUploadPackage *)uploadPackageWithTarget:(GDTCORTarget)target
7272
return uploadPackage;
7373
}
7474

75+
- (void)saveState {
76+
}
77+
7578
- (void)packageDelivered:(GDTCORUploadPackage *)package successful:(BOOL)successful {
7679
dispatch_async(_queue, ^{
7780
for (GDTCOREvent *event in package.events) {

GoogleDataTransportCCTSupport/GDTCCTLibrary/GDTCCTPrioritizer.m

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,17 @@ typedef NS_ENUM(NSInteger, GDTCCTQoSTier) {
131131
GDTCCTQoSWifiOnly = 5,
132132
};
133133

134+
- (void)saveState {
135+
dispatch_sync(_queue, ^{
136+
NSError *error;
137+
GDTCOREncodeArchive(self, ArchivePath(), &error);
138+
if (error) {
139+
GDTCORLogDebug(@"Serializing GDTCCTPrioritizer to an archive failed: %@", error);
140+
}
141+
});
142+
GDTCORLogDebug(@"GDTCCTPrioritizer saved state to %@ as requested by GDT.", ArchivePath());
143+
}
144+
134145
/** Converts a GDTCOREventQoS to a GDTCCTQoS tier.
135146
*
136147
* @param qosTier The GDTCOREventQoS value.

GoogleDataTransportCCTSupport/GDTCCTTests/Integration/GDTCCTIntegrationTest.m

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,10 @@ - (void)generateEventWithQoSTier:(GDTCOREventQoS)qosTier {
9898
GDTCOREvent *event = [self.transport eventForTransport];
9999
event.dataObject = [[GDTCCTTestDataObject alloc] init];
100100
event.qosTier = qosTier;
101-
[self.transport sendDataEvent:event];
101+
[self.transport sendDataEvent:event
102+
onComplete:^(BOOL wasWritten, NSError *_Nullable error) {
103+
NSLog(@"Storing a data event completed.");
104+
}];
102105
dispatch_async(dispatch_get_main_queue(), ^{
103106
self.totalEventsGenerated += 1;
104107
});

0 commit comments

Comments
 (0)