diff --git a/.github/workflows/deploy-private-pod.yml b/.github/workflows/deploy-private-pod.yml index f78e23f5..95e0a71f 100644 --- a/.github/workflows/deploy-private-pod.yml +++ b/.github/workflows/deploy-private-pod.yml @@ -31,4 +31,4 @@ jobs: - name: 'Add Podspec to repo' run: | - pod repo push rudderlabs Rudder.podspec.json + pod repo push rudderlabs Rudder.podspec.json --allow-warnings diff --git a/CHANGELOG.md b/CHANGELOG.md index ae03f817..2aaf966f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [1.29.1](https://github.com/rudderlabs/rudder-sdk-ios/compare/v1.29.0...v1.29.1) (2024-10-07) + + +### Bug Fixes + +* memory issue crash happening on CloudModeProcessor ([ddc2d05](https://github.com/rudderlabs/rudder-sdk-ios/commit/ddc2d057a7d43b4e62ded7ee561bb4779c35e2d6)) + ## [1.29.0](https://github.com/rudderlabs/rudder-sdk-ios/compare/v1.28.1...v1.29.0) (2024-09-05) diff --git a/README.md b/README.md index 58886784..9eb942c5 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@

- +

@@ -39,7 +39,7 @@ The iOS SDK is available through [**CocoaPods**](https://cocoapods.org), [**Cart To install the SDK, simply add the following line to your Podfile: ```xcode -pod 'Rudder', '1.29.0' +pod 'Rudder', '1.29.1' ``` ### Carthage @@ -47,7 +47,7 @@ pod 'Rudder', '1.29.0' For Carthage support, add the following line to your `Cartfile`: ```xcode -github "rudderlabs/rudder-sdk-ios" "v1.29.0" +github "rudderlabs/rudder-sdk-ios" "v1.29.1" ``` > Remember to include the following code in all `.m` and `.h` files where you want to refer to or use the RudderStack SDK classes, as shown: @@ -71,7 +71,7 @@ You can also add the RudderStack iOS SDK via Swift Package Mangaer, via one of t * Enter the package repository (`git@github.com:rudderlabs/rudder-sdk-ios.git`) in the search bar. -* In **Dependency Rule**, select **Up to Next Major Version** and enter `1.29.0` as the value, as shown: +* In **Dependency Rule**, select **Up to Next Major Version** and enter `1.29.1` as the value, as shown: ![Setting dependency](https://user-images.githubusercontent.com/59817155/145574696-8c849749-13e0-40d5-aacb-3fccb5c8e67d.png) @@ -99,7 +99,7 @@ let package = Package( ], dependencies: [ // Dependencies declare other packages that this package depends on. - .package(url: "git@github.com:rudderlabs/rudder-sdk-ios.git", from: "1.29.0") + .package(url: "git@github.com:rudderlabs/rudder-sdk-ios.git", from: "1.29.1") ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. diff --git a/Sources/Classes/Headers/RSVersion.h b/Sources/Classes/Headers/RSVersion.h index 4ab4d27f..cf5b4eab 100644 --- a/Sources/Classes/Headers/RSVersion.h +++ b/Sources/Classes/Headers/RSVersion.h @@ -8,6 +8,6 @@ #ifndef RSVersion_h #define RSVersion_h -NSString *const SDK_VERSION = @"1.29.0"; +NSString *const SDK_VERSION = @"1.29.1"; #endif /* RSVersion_h */ diff --git a/Sources/Classes/RSCloudModeManager.m b/Sources/Classes/RSCloudModeManager.m index 7d50929f..b82675aa 100644 --- a/Sources/Classes/RSCloudModeManager.m +++ b/Sources/Classes/RSCloudModeManager.m @@ -38,50 +38,56 @@ - (void) startCloudModeProcessor { RSCloudModeManager *strongSelf = weakSelf; [RSLogger logDebug:@"RSCloudModeManager: CloudModeProcessor: Starting the Cloud Mode Processor"]; int sleepCount = 0; - while (YES) { - [strongSelf->lock lock]; - RSNetworkResponse* response = nil; - [strongSelf->dbPersistentManager clearOldEventsWithThreshold: strongSelf->config.dbCountThreshold]; - [RSLogger logDebug:@"RSCloudModeManager: CloudModeProcessor: Fetching events to flush to server"]; - RSDBMessage* dbMessage = [strongSelf->dbPersistentManager fetchEventsFromDB:(strongSelf->config.flushQueueSize) ForMode:CLOUDMODE]; - if ((dbMessage.messages.count >= strongSelf->config.flushQueueSize) || (dbMessage.messages.count > 0 && (sleepCount >= strongSelf->config.sleepTimeout))) { - NSString* payload = [RSCloudModeManager getPayloadFromMessages:dbMessage]; - [RSLogger logDebug:[[NSString alloc] initWithFormat:@"RSCloudModeManager: CloudModeProcessor: Payload: %@", payload]]; - [RSLogger logInfo:[[NSString alloc] initWithFormat:@"RSCloudModeManager: CloudModeProcessor: EventCount: %lu", (unsigned long)dbMessage.messageIds.count]]; - [RSMetricsReporter report:SDKMETRICS_CM_EVENT forMetricType:COUNT withProperties:@{SDKMETRICS_TYPE: SDKMETRICS_MESSAGES} andValue:(float)dbMessage.messages.count]; - if (payload != nil) { - response = [strongSelf->networkManager sendNetworkRequest:payload toEndpoint:BATCH_ENDPOINT withRequestMethod:POST]; - if (response.state == NETWORK_SUCCESS) { - [RSLogger logDebug:[[NSString alloc] initWithFormat:@"RSCloudModeManager: CloudModeProcessor: Updating status as CLOUDMODEPROCESSING DONE for events (%@)",[RSUtils getCSVStringFromArray:dbMessage.messageIds]]]; - [RSMetricsReporter report:SDKMETRICS_CM_ATTEMPT_SUCCESS forMetricType:COUNT withProperties:nil andValue:(float)dbMessage.messages.count]; - [strongSelf->dbPersistentManager updateEventsWithIds:dbMessage.messageIds withStatus:CLOUD_MODE_PROCESSING_DONE]; - [strongSelf->dbPersistentManager clearProcessedEventsFromDB]; - sleepCount = 0; - [self->backOff reset]; + @try { + [strongSelf->lock lock]; + RSNetworkResponse* response = nil; + [strongSelf->dbPersistentManager clearOldEventsWithThreshold: strongSelf->config.dbCountThreshold]; + [RSLogger logDebug:@"RSCloudModeManager: CloudModeProcessor: Fetching events to flush to server"]; + RSDBMessage* dbMessage = [strongSelf->dbPersistentManager fetchEventsFromDB:(strongSelf->config.flushQueueSize) ForMode:CLOUDMODE]; + if ((dbMessage.messages.count >= strongSelf->config.flushQueueSize) || (dbMessage.messages.count > 0 && (sleepCount >= strongSelf->config.sleepTimeout))) { + NSString* payload = [RSCloudModeManager getPayloadFromMessages:dbMessage]; + [RSLogger logDebug:[[NSString alloc] initWithFormat:@"RSCloudModeManager: CloudModeProcessor: Payload: %@", payload]]; + [RSLogger logInfo:[[NSString alloc] initWithFormat:@"RSCloudModeManager: CloudModeProcessor: EventCount: %lu", (unsigned long)dbMessage.messageIds.count]]; + [RSMetricsReporter report:SDKMETRICS_CM_EVENT forMetricType:COUNT withProperties:@{SDKMETRICS_TYPE: SDKMETRICS_MESSAGES} andValue:(float)dbMessage.messages.count]; + if (payload != nil) { + response = [strongSelf->networkManager sendNetworkRequest:payload toEndpoint:BATCH_ENDPOINT withRequestMethod:POST]; + if (response.state == NETWORK_SUCCESS) { + [RSLogger logDebug:[[NSString alloc] initWithFormat:@"RSCloudModeManager: CloudModeProcessor: Updating status as CLOUDMODEPROCESSING DONE for events (%@)",[RSUtils getCSVStringFromArray:dbMessage.messageIds]]]; + [RSMetricsReporter report:SDKMETRICS_CM_ATTEMPT_SUCCESS forMetricType:COUNT withProperties:nil andValue:(float)dbMessage.messages.count]; + [strongSelf->dbPersistentManager updateEventsWithIds:dbMessage.messageIds withStatus:CLOUD_MODE_PROCESSING_DONE]; + [strongSelf->dbPersistentManager clearProcessedEventsFromDB]; + sleepCount = 0; + [self->backOff reset]; + } } } + [strongSelf->lock unlock]; + [RSLogger logDebug:[[NSString alloc] initWithFormat:@"RSCloudModeManager: CloudModeProcessor: cloudModeSleepCount: %d", sleepCount]]; + sleepCount += 1; + + if(response == nil) { + sleep(1); + } else if (response.state == WRONG_WRITE_KEY) { + [RSLogger logError:@"RSCloudModeManager: CloudModeProcessor: Wrong WriteKey. Aborting the Cloud Mode Processor"]; + break; + } else if (response.state == INVALID_URL) { + [RSLogger logError:@"RSCloudModeManager: CloudModeProcessor: Invalid Data Plane URL. Aborting the Cloud Mode Processor"]; + [RSMetricsReporter report:SDKMETRICS_CM_ATTEMPT_ABORT forMetricType:COUNT withProperties:@{SDKMETRICS_TYPE: SDKMETRICS_DATA_PLANE_URL_INVALID} andValue:1]; + break; + } else if (response.state == NETWORK_ERROR) { + int delay = [self->backOff nextDelay]; + [RSLogger logDebug:[[NSString alloc] initWithFormat:@"RSCloudModeManager: CloudModeProcessor: Retrying in: %@", [RSUtils secondsToString:delay]]]; + [RSMetricsReporter report:SDKMETRICS_CM_ATTEMPT_RETRY forMetricType:COUNT withProperties:nil andValue:1]; + sleep(delay); + } else { // To handle the status code RESOURCE_NOT_FOUND(404) & BAD_REQUEST(400) + [RSLogger logDebug:[[NSString alloc] initWithFormat:@"RSCloudModeManager: CloudModeProcessor: Retrying in: 1s"]]; + sleep(1); + } } - [strongSelf->lock unlock]; - [RSLogger logDebug:[[NSString alloc] initWithFormat:@"RSCloudModeManager: CloudModeProcessor: cloudModeSleepCount: %d", sleepCount]]; - sleepCount += 1; - - if(response == nil) { - sleep(1); - } else if (response.state == WRONG_WRITE_KEY) { - [RSLogger logError:@"RSCloudModeManager: CloudModeProcessor: Wrong WriteKey. Aborting the Cloud Mode Processor"]; - break; - } else if (response.state == INVALID_URL) { - [RSLogger logError:@"RSCloudModeManager: CloudModeProcessor: Invalid Data Plane URL. Aborting the Cloud Mode Processor"]; - [RSMetricsReporter report:SDKMETRICS_CM_ATTEMPT_ABORT forMetricType:COUNT withProperties:@{SDKMETRICS_TYPE: SDKMETRICS_DATA_PLANE_URL_INVALID} andValue:1]; - break; - } else if (response.state == NETWORK_ERROR) { - int delay = [self->backOff nextDelay]; - [RSLogger logDebug:[[NSString alloc] initWithFormat:@"RSCloudModeManager: CloudModeProcessor: Retrying in: %@", [RSUtils secondsToString:delay]]]; - [RSMetricsReporter report:SDKMETRICS_CM_ATTEMPT_RETRY forMetricType:COUNT withProperties:nil andValue:1]; - sleep(delay); - } else { // To handle the status code RESOURCE_NOT_FOUND(404) & BAD_REQUEST(400) - [RSLogger logDebug:[[NSString alloc] initWithFormat:@"RSCloudModeManager: CloudModeProcessor: Retrying in: 1s"]]; + @catch (NSException *exception) { + [strongSelf->lock unlock]; + [RSLogger logError:[NSString stringWithFormat:@"RSCloudModeManager: CloudModeProcessor: Failed to flush current batch, reason: %@", exception.reason]]; sleep(1); } } diff --git a/Sources/Classes/RSDBPersistentManager.m b/Sources/Classes/RSDBPersistentManager.m index 0f84a73e..65c56d36 100644 --- a/Sources/Classes/RSDBPersistentManager.m +++ b/Sources/Classes/RSDBPersistentManager.m @@ -491,30 +491,39 @@ -(RSDBMessage*) fetchAllEventsFromDBForMode:(MODES) mode { - (RSDBMessage *) getEventsFromDB :(NSString*) querySQLString { [RSLogger logDebug:[[NSString alloc] initWithFormat:@"RSDBPersistentManager: getEventsFromDB: fetchEventSql: %@", querySQLString]]; + const char* querySQL = [querySQLString UTF8String]; - NSMutableArray *messageIds = [[NSMutableArray alloc] init]; - NSMutableArray *messages = [[NSMutableArray alloc] init]; - NSMutableArray* statusList = [[NSMutableArray alloc] init]; - NSMutableArray* dmProcessedList = [[NSMutableArray alloc] init]; + NSMutableArray *messageIds = [NSMutableArray array]; + NSMutableArray *messages = [NSMutableArray array]; + NSMutableArray *statusList = [NSMutableArray array]; + NSMutableArray *dmProcessedList = [NSMutableArray array]; @synchronized (self) { - void *queryStmt = nil; + sqlite3_stmt *queryStmt = nil; if ([database prepare_v2:querySQL nBytes:-1 ppStmt:&queryStmt pzTail:NULL] == SQLITE_OK) { [RSLogger logDebug:@"RSDBPersistentManager: getEventsFromDB: Successfully fetched events from DB"]; while ([database step:queryStmt] == SQLITE_ROW) { - int messageId = [database column_int:queryStmt i:0]; - const unsigned char* queryResultCol1 = [database column_text:queryStmt i:1]; - NSString *message = [[NSString alloc] initWithUTF8String:(char *)queryResultCol1]; - int status = [database column_int:queryStmt i:3]; - int dmProcessed = [database column_int:queryStmt i:4]; - [messageIds addObject:[[NSString alloc] initWithFormat:@"%d", messageId]]; - [messages addObject:message]; - [statusList addObject:[NSNumber numberWithInt:status]]; - [dmProcessedList addObject:[NSNumber numberWithInt:dmProcessed]]; + @autoreleasepool { + int messageId = [database column_int:queryStmt i:0]; + const unsigned char* queryResultCol1 = [database column_text:queryStmt i:1]; + NSString *message = [[NSString alloc] initWithUTF8String:(char *)queryResultCol1]; + int status = [database column_int:queryStmt i:3]; + int dmProcessed = [database column_int:queryStmt i:4]; + + [messageIds addObject:[[NSString alloc] initWithFormat:@"%d", messageId]]; + [messages addObject:message]; + [statusList addObject:[NSNumber numberWithInt:status]]; + [dmProcessedList addObject:[NSNumber numberWithInt:dmProcessed]]; + } } } else { [RSLogger logError:@"RSDBPersistentManager: getEventsFromDB: Failed to fetch events from DB"]; } + + // Finalize the SQL statement to free resources + if (queryStmt != nil) { + [database finalize:queryStmt]; + } } RSDBMessage *dbMessage = [[RSDBMessage alloc] init]; diff --git a/package.json b/package.json index f6923f55..fc9b2347 100644 --- a/package.json +++ b/package.json @@ -1,4 +1,4 @@ { - "version": "1.29.0", + "version": "1.29.1", "description": "Rudder is a platform for collecting, storing and routing customer event data to dozens of tools" } diff --git a/sonar-project.properties b/sonar-project.properties index 47d48970..addfe06b 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -6,7 +6,7 @@ sonar.qualitygate.wait=false sonar.projectKey=rudderlabs_rudder-sdk-ios sonar.organization=rudderlabs sonar.projectName=RudderStack iOS SDK -sonar.projectVersion=1.29.0 +sonar.projectVersion=1.29.1 # C/C++/Objective-C related details # sonar.cfamily.compile-commands=compile_commands.json