From 2e7d68741283c65aaaa07e007c5262f120003a01 Mon Sep 17 00:00:00 2001 From: Semsudin Tafilovic Date: Wed, 15 May 2024 12:11:48 +0200 Subject: [PATCH] Published version 5.1.9 --- CHANGELOG.md | 4 + android-sdk/gradle.properties | 2 +- .../android/sdk/core/SchedulerImplTest.kt | 321 ++++++++++++++---- .../android/sdk/core/SchedulerImpl.kt | 21 +- .../android/sdk/domain/external/Optout.kt | 4 +- .../sdk/domain/worker/SendRequestsWorker.kt | 168 +++++---- build.gradle | 2 +- .../webtrekk/androidsdk/SampleApplication.kt | 2 +- 8 files changed, 345 insertions(+), 179 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c8ec4816..b8b786eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# Change Log +## Version 5.1.9 *(2024-05-15)* +* Fixed bug - duplicate request are sent when application starts with optOut set to true, and there are some requests previously stored in the database. + # Change Log ## Version 5.1.8 *(2024-03-27)* * Fixed unexpected tracking behaviour for media tracking diff --git a/android-sdk/gradle.properties b/android-sdk/gradle.properties index 78cb6916..29474fe0 100644 --- a/android-sdk/gradle.properties +++ b/android-sdk/gradle.properties @@ -23,7 +23,7 @@ # # LIBRARY_VERSION=5.1.4.3 (hotfixes are included on this variable) # -LIBRARY_VERSION=5.1.8.1 +LIBRARY_VERSION=5.1.9 BINTRAY_REPO=webtrekk-android-sdk BINRTAY_NAME=webtrekk-android-sdk PUBLISHED_GROUP_ID=com.mapp.sdk diff --git a/android-sdk/src/androidTest/java/webtrekk/android/sdk/core/SchedulerImplTest.kt b/android-sdk/src/androidTest/java/webtrekk/android/sdk/core/SchedulerImplTest.kt index ed4e4993..be341558 100644 --- a/android-sdk/src/androidTest/java/webtrekk/android/sdk/core/SchedulerImplTest.kt +++ b/android-sdk/src/androidTest/java/webtrekk/android/sdk/core/SchedulerImplTest.kt @@ -5,18 +5,33 @@ import android.util.Log import androidx.test.platform.app.InstrumentationRegistry import androidx.work.Configuration import androidx.work.Constraints +import androidx.work.CoroutineWorker +import androidx.work.Data +import androidx.work.ListenableWorker +import androidx.work.OneTimeWorkRequest import androidx.work.WorkInfo import androidx.work.WorkManager import androidx.work.WorkQuery +import androidx.work.WorkerParameters +import androidx.work.await import androidx.work.testing.SynchronousExecutor import androidx.work.testing.WorkManagerTestInitHelper +import io.mockk.coEvery +import io.mockk.mockkClass import io.mockk.spyk +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import org.hamcrest.MatcherAssert import org.junit.After import org.junit.Before import org.junit.Test import webtrekk.android.sdk.Config +import webtrekk.android.sdk.Webtrekk import webtrekk.android.sdk.WebtrekkConfiguration import webtrekk.android.sdk.domain.worker.CleanUpWorker import webtrekk.android.sdk.domain.worker.SendRequestsWorker @@ -26,6 +41,7 @@ class SchedulerImplTest { private lateinit var context: Context private lateinit var config: Config private lateinit var workManager: WorkManager + private val mutex = Mutex() @Before fun setUp() { @@ -34,6 +50,8 @@ class SchedulerImplTest { context = InstrumentationRegistry.getInstrumentation().targetContext config = spyk(WebtrekkConfiguration.Builder(ids, domain).build()) + Webtrekk.getInstance().init(context, config) + val workManagerConfig = Configuration.Builder() .setExecutor(SynchronousExecutor()) .setMinimumLoggingLevel(Log.DEBUG) @@ -43,111 +61,266 @@ class SchedulerImplTest { workManager = WorkManager.getInstance(context) scheduler = spyk(SchedulerImpl(workManager, config)) + + val mockWorker = + mockkClass(SendRequestsWorker::class, relaxed = true, relaxUnitFun = true) + coEvery { mockWorker.doWork() } coAnswers { + mutex.withLock { + delay(300) // simulate some work + return@withLock ListenableWorker.Result.success() + } + } } @After fun tearDown() { - workManager.cancelAllWork() - workManager.pruneWork() - WorkManagerTestInitHelper.closeWorkDatabase() + runBlocking { + workManager.cancelAllWork().await() + workManager.pruneWork().await() + WorkManagerTestInitHelper.closeWorkDatabase() + } } @Test - fun schedule_Periodic_and_Onetime_request_executes_only_periodic() { - scheduler.scheduleSendRequests(1L, Constraints.Builder().build()) - scheduler.sendRequestsThenCleanUp() - val works = workManager.getWorkInfosByTag(SendRequestsWorker.TAG).get() - MatcherAssert.assertThat( - "Only one work for sending request are running", - works.filter { it.state in listOf(WorkInfo.State.RUNNING, WorkInfo.State.SUCCEEDED) }.size == 1 - ) - MatcherAssert.assertThat( - "First called Periodic Request is executed only", - works.firstOrNull()?.periodicityInfo != null - ) + fun schedule_periodicRequest_and_oneTime_request_executes_executes_synchronized() { + runBlocking { + // we start both works at the same time + scheduler.scheduleSendRequests(1L, Constraints.Builder().build()) + scheduler.sendRequestsThenCleanUp() + //wait 400 milliseconds and check result + delay(400) + val works = workManager.getWorkInfosByTag(SendRequestsWorker.TAG).await() + MatcherAssert.assertThat( + "Only one work for sending request is finished", + works.filter { + it.state in listOf( + WorkInfo.State.SUCCEEDED + ) + }.size == 1 + ) + } } @Test - fun schedule_OneTime_and_Periodic_request_executes_only_OneTime_request() { - scheduler.sendRequestsThenCleanUp() - scheduler.scheduleSendRequests(1L, Constraints.Builder().build()) - val works = workManager.getWorkInfosByTag(SendRequestsWorker.TAG).get() - MatcherAssert.assertThat( - "Only one work for sending request are running or it is succeeded", - works.filter { - it.state in listOf( - WorkInfo.State.SUCCEEDED, - WorkInfo.State.RUNNING - ) - }.size == 1 - ) + fun schedule_oneTime_and_periodicRequest_executes_synchronized() { + runBlocking { + // we start both works at the same time + scheduler.sendRequestsThenCleanUp() + scheduler.scheduleSendRequests(1L, Constraints.Builder().build()) + //wait 400 milliseconds and check result + delay(400) + val works = workManager.getWorkInfosByTag(SendRequestsWorker.TAG).await() + println(works.toString()) + MatcherAssert.assertThat( + "Only one work for sending request are running or it is succeeded", + works.filter { + it.state in listOf( + WorkInfo.State.SUCCEEDED, + ) + }.size == 1 + ) + } } @Test fun trigger_only_one_time_requests_for_sending_and_cleaning_data() { - scheduler.sendRequestsThenCleanUp() - val works = workManager.getWorkInfosByTag(SendRequestsWorker.TAG).get() - MatcherAssert.assertThat( - "One time request is triggered", - works.firstOrNull()?.periodicityInfo == null - ) + runBlocking { + scheduler.sendRequestsThenCleanUp() + val works = workManager.getWorkInfosByTag(SendRequestsWorker.TAG).await() + MatcherAssert.assertThat( + "One time request is triggered", + works.firstOrNull()?.periodicityInfo == null + ) + } } @Test fun trigger_cleanup_worker_as_a_chain_work_of_one_time_request() { - scheduler.sendRequestsThenCleanUp() - val works = workManager.getWorkInfosByTag(CleanUpWorker.TAG).get() - MatcherAssert.assertThat( - "One time request is triggered", - works.firstOrNull()?.periodicityInfo == null - ) + runBlocking { + scheduler.sendRequestsThenCleanUp() + val works = workManager.getWorkInfosByTag(CleanUpWorker.TAG).await() + MatcherAssert.assertThat( + "One time request is triggered", + works.firstOrNull()?.periodicityInfo == null + ) + } } @Test fun trigger_periodic_work_request() { - scheduler.scheduleSendRequests(15, Constraints.Builder().build()) - val works = workManager.getWorkInfosByTag(SendRequestsWorker.TAG).get() - MatcherAssert.assertThat( - "Periodic work request is triggered", - works.firstOrNull()?.periodicityInfo != null - ) + runBlocking { + scheduler.scheduleSendRequests(15, Constraints.Builder().build()) + val works = workManager.getWorkInfosByTag(SendRequestsWorker.TAG).await() + MatcherAssert.assertThat( + "Periodic work request is triggered", + works.firstOrNull()?.periodicityInfo != null + ) + } } @Test fun schedule_and_cancel_all_onetime_work_requests() { - val tags=listOf( - SendRequestsWorker.TAG, - CleanUpWorker.TAG - ) - val validWorkStates=listOf(WorkInfo.State.RUNNING,WorkInfo.State.ENQUEUED) - val workQuery=WorkQuery.fromTags(tags) - var workCount:Int=0 - scheduler.sendRequestsThenCleanUp() - workCount = workManager.getWorkInfos(workQuery).get().filter { it.state in validWorkStates }.size + runBlocking { + val tags = listOf( + SendRequestsWorker.TAG, + CleanUpWorker.TAG + ) + val validWorkStates = + listOf(WorkInfo.State.RUNNING, WorkInfo.State.SUCCEEDED, WorkInfo.State.ENQUEUED) + val workQuery = WorkQuery.fromTags(tags) + var workCount: Int = 0 + scheduler.sendRequestsThenCleanUp() + workCount = + workManager.getWorkInfos(workQuery).await() + .filter { it.state in validWorkStates }.size - MatcherAssert.assertThat("Work count should be 2", workCount==2) - tags.forEach { workManager.cancelAllWorkByTag(it) } + MatcherAssert.assertThat("Work count should be 2", workCount == 2) + for (tag in tags) { + workManager.cancelAllWorkByTag(tag).await() + } - workCount=workManager.getWorkInfos(workQuery).get().filter { it.state in validWorkStates }.size - MatcherAssert.assertThat("Work count should be 0", workCount==0) + workCount = workManager.getWorkInfos(workQuery).await() + .filter { it.state == WorkInfo.State.RUNNING }.size + MatcherAssert.assertThat("Work count should be 0", workCount == 0) + } } @Test fun schedule_and_cancel_all_periodic_work_requests() { - val tags=listOf( - SendRequestsWorker.TAG, - CleanUpWorker.TAG - ) - val validWorkStates=listOf(WorkInfo.State.RUNNING,WorkInfo.State.ENQUEUED) - val workQuery=WorkQuery.fromTags(tags) - var workCount:Int=0 - scheduler.scheduleSendRequests(15, Constraints.Builder().build()) - workCount = workManager.getWorkInfos(workQuery).get().filter { it.state in validWorkStates }.size - - MatcherAssert.assertThat("Work count should be 1", workCount==1) - tags.forEach { workManager.cancelAllWorkByTag(it) } - - workCount=workManager.getWorkInfos(workQuery).get().filter { it.state in validWorkStates }.size - MatcherAssert.assertThat("Work count should be 0", workCount==0) + runBlocking { + val tags = listOf( + SendRequestsWorker.TAG, + CleanUpWorker.TAG + ) + val validWorkStates = listOf(WorkInfo.State.RUNNING, WorkInfo.State.ENQUEUED) + val workQuery = WorkQuery.fromTags(tags) + var workCount: Int = 0 + scheduler.scheduleSendRequests(15, Constraints.Builder().build()) + workCount = + workManager.getWorkInfos(workQuery).get() + .filter { it.state in validWorkStates }.size + + MatcherAssert.assertThat("Work count should be 1", workCount == 1) + tags.forEach { workManager.cancelAllWorkByTag(it) } + + workCount = + workManager.getWorkInfos(workQuery).get() + .filter { it.state in validWorkStates }.size + MatcherAssert.assertThat("Work count should be 0", workCount == 0) + } + } + + /** + * Send different input values for every worker. It needs to do some simple computation. If works are synchronized + * every work should return 0 value. + */ + @Test + fun test_if_multiple_workers_started_are_synchronized() { + runBlocking { + val request1 = OneTimeWorkRequest.Builder(TestWorker::class.java) + .setInputData(Data.Builder().putInt("value", 1).build()) + .build() + + val request2 = OneTimeWorkRequest.Builder(TestWorker::class.java) + .setInputData(Data.Builder().putInt("value", 2).build()) + .build() + + val request3 = OneTimeWorkRequest.Builder(TestWorker::class.java) + .setInputData(Data.Builder().putInt("value", 3).build()) + .build() + + val query = WorkQuery.fromIds( + listOf( + request1.id, + request2.id, + request3.id + ) + ) + + workManager.enqueue(request1) + workManager.enqueue(request2) + workManager.enqueue(request3) + + var info = workManager.getWorkInfos(query).await() + + while (info.any { it.state == WorkInfo.State.RUNNING }) { + delay(100) + info = workManager.getWorkInfos(query).await() + } + + println(info.toString()) + val valid = info.filter { + it.outputData.getInt( + "value", + 0 + ) == 0 + }.size + + MatcherAssert.assertThat("3 Workers are returned 0 value", info.size == valid) + } + } + + @Test + fun test_synchronization_of_single_method() { + val counter = Counter() + + val job1 = GlobalScope.launch { + repeat(1000) { + counter.increment() + } + } + + val job2 = GlobalScope.launch { + repeat(1000) { + counter.increment() + } + } + + runBlocking { + job1.join() + job2.join() + val result = counter.getCount() + println(result) + MatcherAssert.assertThat("Result should be 2000", 2000 == result) + } + } +} + + +class TestWorker(context: Context, parameters: WorkerParameters) : + CoroutineWorker(context, parameters) { + var value = 0 + override suspend fun doWork(): Result = coroutineScope { + mutex.withLock { + val inc = inputData.getInt("value", 1) + value += inc + delay(300) + value -= inc + val outputData = Data.Builder().put("value", value).build() + return@coroutineScope Result.success(outputData) + } + } + + companion object { + val TAG = TestWorker::class.java.simpleName + val mutex = Mutex() + } +} + +class Counter { + private var count = 0 + + suspend fun increment() { + mutex.withLock { + count++ + } + } + + fun getCount(): Int { + return count + } + + companion object{ + val mutex= Mutex() } } \ No newline at end of file diff --git a/android-sdk/src/main/java/webtrekk/android/sdk/core/SchedulerImpl.kt b/android-sdk/src/main/java/webtrekk/android/sdk/core/SchedulerImpl.kt index 53461238..8e432bb0 100644 --- a/android-sdk/src/main/java/webtrekk/android/sdk/core/SchedulerImpl.kt +++ b/android-sdk/src/main/java/webtrekk/android/sdk/core/SchedulerImpl.kt @@ -39,6 +39,7 @@ import kotlinx.coroutines.sync.Mutex import webtrekk.android.sdk.Config import webtrekk.android.sdk.domain.worker.CleanUpWorker import webtrekk.android.sdk.domain.worker.SendRequestsWorker +import webtrekk.android.sdk.util.webtrekkLogger import java.util.concurrent.TimeUnit /** @@ -55,10 +56,8 @@ internal class SchedulerImpl( repeatInterval: Long, constraints: Constraints, ) { + webtrekkLogger.debug("SEND WORKER - scheduleSendRequests") synchronized(mutex) { - val workers = workManager.getWorkInfosByTag(SendRequestsWorker.TAG).get() - val isRunning = workers.any { it.state in listOf(WorkInfo.State.RUNNING) } - val data = Data.Builder().apply { putStringArray("trackIds", config.trackIds.toTypedArray()) putString("trackDomain", config.trackDomain) @@ -69,7 +68,7 @@ internal class SchedulerImpl( repeatInterval, TimeUnit.MINUTES ).setConstraints(constraints) - .setInitialDelay(if (isRunning) 15 else 0, TimeUnit.MINUTES) + .setInitialDelay(0, TimeUnit.MILLISECONDS) .setInputData(data) .addTag(SendRequestsWorker.TAG) @@ -77,20 +76,22 @@ internal class SchedulerImpl( workManager.enqueueUniquePeriodicWork( SEND_REQUESTS_WORKER, - ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE, + ExistingPeriodicWorkPolicy.UPDATE, sendRequestsWorker ) } } override fun sendRequestsThenCleanUp() { + webtrekkLogger.debug("SEND WORKER - sendRequestsThenCleanUp") synchronized(mutex) { // check if SendRequestsWorker already running as periodic work request - val future = workManager.getWorkInfosByTag(SendRequestsWorker.TAG) - val workers = future.get() - if (workers.none { it.state in listOf(WorkInfo.State.RUNNING) }) { - scheduleSendAndCleanWorkers() - } +// val future = workManager.getWorkInfosByTag(SendRequestsWorker.TAG) +// val workers = future.get() +// if (workers.none { it.state in listOf(WorkInfo.State.RUNNING) }) { +// scheduleSendAndCleanWorkers() +// } + scheduleSendAndCleanWorkers() } } diff --git a/android-sdk/src/main/java/webtrekk/android/sdk/domain/external/Optout.kt b/android-sdk/src/main/java/webtrekk/android/sdk/domain/external/Optout.kt index 203e5e43..b22a5e8e 100644 --- a/android-sdk/src/main/java/webtrekk/android/sdk/domain/external/Optout.kt +++ b/android-sdk/src/main/java/webtrekk/android/sdk/domain/external/Optout.kt @@ -67,6 +67,8 @@ internal class Optout( // If opt out value is set to true, then disable tracking data, cancel all work manager workers and delete or send then delete current data in the data base. if (invokeParams.optOutValue) { + appState.disable(invokeParams.context) // Disable the auto track + scheduler.cancelScheduleSendRequests() // Cancel the work manager workers // If sendCurrentData is true, then one time worker will send current data requests to the server, then clean up the data base. if (invokeParams.sendCurrentData) { scheduler.sendRequestsThenCleanUp() @@ -82,8 +84,6 @@ internal class Optout( .onFailure { logger.error("Failed to clear the track requests while opting out") } } } - appState.disable(invokeParams.context) // Disable the auto track - scheduler.cancelScheduleSendRequests() // Cancel the work manager workers } } diff --git a/android-sdk/src/main/java/webtrekk/android/sdk/domain/worker/SendRequestsWorker.kt b/android-sdk/src/main/java/webtrekk/android/sdk/domain/worker/SendRequestsWorker.kt index 859640a7..4148c2e6 100644 --- a/android-sdk/src/main/java/webtrekk/android/sdk/domain/worker/SendRequestsWorker.kt +++ b/android-sdk/src/main/java/webtrekk/android/sdk/domain/worker/SendRequestsWorker.kt @@ -28,10 +28,14 @@ package webtrekk.android.sdk.domain.worker import android.content.Context import android.util.Log import androidx.work.CoroutineWorker +import androidx.work.Data +import androidx.work.WorkInfo import androidx.work.WorkManager import androidx.work.WorkerParameters import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.delay +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.withContext import webtrekk.android.sdk.BuildConfig import webtrekk.android.sdk.Webtrekk @@ -47,8 +51,6 @@ import webtrekk.android.sdk.extension.buildUrlRequest import webtrekk.android.sdk.extension.stringifyRequestBody import webtrekk.android.sdk.module.AppModule import webtrekk.android.sdk.module.InteractorModule -import webtrekk.android.sdk.module.LibraryModule -import webtrekk.android.sdk.util.CoroutineDispatchers import webtrekk.android.sdk.util.batchSupported import webtrekk.android.sdk.util.requestPerBatch @@ -60,118 +62,104 @@ internal class SendRequestsWorker( workerParameters: WorkerParameters ) : CoroutineWorker(context, workerParameters) { - override suspend fun doWork(): Result = coroutineScope { - Log.d(TAG, "doWork - starting... ${tags.joinToString(separator = ", ")}") - // this check and initialization is needed for cross platform solutions - if (!Webtrekk.getInstance().isInitialized()) { - val configJson = WebtrekkSharedPrefs(applicationContext).configJson - val config = WebtrekkConfiguration.fromJson(configJson) - Webtrekk.getInstance().init(applicationContext, config) - Log.d(TAG, "doWork - initialized!") - } - - /** - * [coroutineDispatchers] the injected coroutine dispatchers. - */ - /** - * [coroutineDispatchers] the injected coroutine dispatchers. - */ - val coroutineDispatchers: CoroutineDispatchers = AppModule.dispatchers + withContext(AppModule.dispatchers.ioDispatcher) { + mutex.withLock { + Log.d(TAG, "doWork - starting... ${tags.joinToString(separator = ", ")}") + // this check and initialization is needed for cross platform solutions + if (!Webtrekk.getInstance().isInitialized()) { + val configJson = WebtrekkSharedPrefs(applicationContext).configJson + val config = WebtrekkConfiguration.fromJson(configJson) + Webtrekk.getInstance().init(applicationContext, config) + Log.d(TAG, "doWork - initialized!") + } - /** - * [getCachedDataTracks] the injected internal interactor for getting the data from the data base. - */ - /** - * [getCachedDataTracks] the injected internal interactor for getting the data from the data base. - */ - val getCachedDataTracks: GetCachedDataTracks = - InteractorModule.getCachedDataTracks() + /** + * [getCachedDataTracks] the injected internal interactor for getting the data from the data base. + */ + val getCachedDataTracks: GetCachedDataTracks = + InteractorModule.getCachedDataTracks() - /** - * [executeRequest] the injected internal interactor for executing the requests. - */ - /** - * [executeRequest] the injected internal interactor for executing the requests. - */ - val executeRequest: ExecuteRequest = InteractorModule.executeRequest() + /** + * [executeRequest] the injected internal interactor for executing the requests. + */ + val executeRequest: ExecuteRequest = InteractorModule.executeRequest() - /** - * [ExecutePostRequest] the injected internal interactor for executing the requests. - */ - /** - * [ExecutePostRequest] the injected internal interactor for executing the requests. - */ - val executePostRequest: ExecutePostRequest = InteractorModule.executePostRequest() + /** + * [ExecutePostRequest] the injected internal interactor for executing the requests. + */ + val executePostRequest: ExecutePostRequest = + InteractorModule.executePostRequest() - /** - * [logger] the injected logger from Webtrekk. - */ - /** - * [logger] the injected logger from Webtrekk. - */ - val logger by lazy { AppModule.logger } + /** + * [logger] the injected logger from Webtrekk. + */ + val logger by lazy { AppModule.logger } - val activeConfig = Webtrekk.getInstance().getCurrentConfiguration() + val activeConfig = Webtrekk.getInstance().getCurrentConfiguration() - // retrieves the data in the data base with state of NEW or FAILED only. - withContext(coroutineDispatchers.ioDispatcher) { - getCachedDataTracks( - GetCachedDataTracks.Params( - requestStates = listOf( - TrackRequest.RequestState.NEW, - TrackRequest.RequestState.FAILED + // retrieves the data in the data base with state of NEW or FAILED only. + logger.debug("SEND WORKER - START ${this@SendRequestsWorker}") + getCachedDataTracks( + GetCachedDataTracks.Params( + requestStates = listOf( + TrackRequest.RequestState.NEW, + TrackRequest.RequestState.FAILED + ) ) ) - ) - .onSuccess { dataTracks -> - if (dataTracks.isNotEmpty()) { - logger.info("Executing the requests") - // Must execute requests sync and in order - if (batchSupported) { - // group requests by everId - dataTracks.asSequence() - .batch(requestPerBatch) - .forEach { dataTrack -> - val urlRequest = dataTrack.buildPostRequest(activeConfig) - logger.info("Sending request = $urlRequest, Request Body= " + urlRequest.stringifyRequestBody()) + .onSuccess { dataTracks -> + if (dataTracks.isNotEmpty()) { + logger.info("Executing the requests") + // Must execute requests sync and in order + if (batchSupported) { + // group requests by everId + dataTracks.asSequence() + .batch(requestPerBatch) + .forEach { dataTrack -> + val urlRequest = + dataTrack.buildPostRequest(activeConfig) + logger.info("Sending request = $urlRequest, Request Body= " + urlRequest.stringifyRequestBody()) + + executePostRequest( + ExecutePostRequest.Params( + request = urlRequest, + dataTracks = dataTracks + ) + ) + .onSuccess { logger.debug("Sent the request successfully $it") } + .onFailure { logger.error("Failed to send the request $it") } + } + } else { + dataTracks.forEach { dataTrack -> + val urlRequest = dataTrack.buildUrlRequest(activeConfig) + logger.info("Sending request = $urlRequest") - executePostRequest( - ExecutePostRequest.Params( + executeRequest( + ExecuteRequest.Params( request = urlRequest, - dataTracks = dataTracks + dataTrack = dataTrack ) ) .onSuccess { logger.debug("Sent the request successfully $it") } .onFailure { logger.error("Failed to send the request $it") } } - } else { - dataTracks.forEach { dataTrack -> - val urlRequest = dataTrack.buildUrlRequest(activeConfig) - logger.info("Sending request = $urlRequest") - - executeRequest( - ExecuteRequest.Params( - request = urlRequest, - dataTrack = dataTrack - ) - ) - .onSuccess { logger.debug("Sent the request successfully $it") } - .onFailure { logger.error("Failed to send the request $it") } } } - } - if (BuildConfig.DEBUG) { - logger.debug(activeConfig.printUsageStatisticCalculation()) + if (BuildConfig.DEBUG) { + logger.debug(activeConfig.printUsageStatisticCalculation()) + } } - } - .onFailure { logger.error("Error getting cached data tracks: $it") } + .onFailure { logger.error("Error getting cached data tracks: $it") } + logger.debug("SEND WORKER - END ${this@SendRequestsWorker}") + } + return@withContext Result.success() } - Result.success() } companion object { + private val mutex = Mutex() const val TAG = "send_track_requests" const val TAG_ONE_TIME_WORKER = "send_track_requests_now" } diff --git a/build.gradle b/build.gradle index 1977def3..7b64eec1 100644 --- a/build.gradle +++ b/build.gradle @@ -30,7 +30,7 @@ apply plugin: 'io.codearte.nexus-staging' buildscript { ext.versions = [ - 'webtrekkVersion' : '5.1.8', + 'webtrekkVersion' : '5.1.9', 'gradleVersion' : '3.6.4', 'kotlinVersion' : '1.9.23',//'1.4.32', 'gradleVersionsPlugin' : '0.21.0', diff --git a/sample/src/main/java/com/example/webtrekk/androidsdk/SampleApplication.kt b/sample/src/main/java/com/example/webtrekk/androidsdk/SampleApplication.kt index 11545bd4..c98c643d 100644 --- a/sample/src/main/java/com/example/webtrekk/androidsdk/SampleApplication.kt +++ b/sample/src/main/java/com/example/webtrekk/androidsdk/SampleApplication.kt @@ -75,7 +75,7 @@ class SampleApplication : Application() { Webtrekk.getInstance().init(context = this, config = webtrekkConfigurations) Webtrekk.getInstance().apply { - optOut(false,true) + optOut(true,true) // anonymousTracking(false, emptySet()) // setEverId(null) // setTemporarySessionId("user-xyz-123456789")