Skip to content

Commit

Permalink
Merge branch 'release/5.5.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
matus-tomlein committed Oct 2, 2023
2 parents 9d541a5 + 992c7b7 commit 0605fd0
Show file tree
Hide file tree
Showing 13 changed files with 91 additions and 11 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
Version 5.5.0 (2023-10-02)
--------------------------
Add option to disable retrying any failed requests (#641)

Version 5.4.4 (2023-09-05)
--------------------------
Fix invalid consent document context entity in case no name or description is given (#637)
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
5.4.4
5.5.0
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ plugins {

subprojects {
group = 'com.snowplowanalytics'
version = '5.4.4'
version = '5.5.0'
repositories {
google()
maven {
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ systemProp.org.gradle.internal.http.socketTimeout=120000
SONATYPE_STAGING_PROFILE=comsnowplowanalytics
GROUP=com.snowplowanalytics
POM_ARTIFACT_ID=snowplow-android-tracker
VERSION_NAME=5.4.4
VERSION_NAME=5.5.0

POM_NAME=snowplow-android-tracker
POM_PACKAGING=aar
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,28 @@ class EmitterTest {
emitter.flush()
}

@Test
@Throws(InterruptedException::class)
fun testDoesNotRetryFailedRequestsIfDisabled() {
val networkConnection = MockNetworkConnection(HttpMethod.GET, 500)
val emitter = getEmitter(networkConnection, BufferOption.Single)
emitter.retryFailedRequests = false

// no events in queue since they were dropped because retrying is disabled
emitter.add(generatePayloads(1)[0])
Thread.sleep(1000)
Assert.assertEquals(0, emitter.eventStore!!.size())

emitter.retryFailedRequests = true
emitter.add(generatePayloads(1)[0])
Thread.sleep(1000)

// event still in queue because retrying is enabled
Assert.assertEquals(1, emitter.eventStore!!.size())
Assert.assertEquals(2, networkConnection.previousResults.size.toLong())
emitter.flush()
}

// Emitter Builder
private fun getEmitter(networkConnection: NetworkConnection?, option: BufferOption?): Emitter {
val builder = { emitter: Emitter ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,29 +26,29 @@ class RequestResultTest {
val result = RequestResult(200, false, listOf(100L))
Assert.assertTrue(result.isSuccessful)
Assert.assertFalse(result.oversize)
Assert.assertFalse(result.shouldRetry(HashMap()))
Assert.assertFalse(result.shouldRetry(HashMap(), true))
Assert.assertEquals(result.eventIds, listOf(100L))
}

@Test
fun testFailedRequest() {
val result = RequestResult(500, false, ArrayList())
Assert.assertFalse(result.isSuccessful)
Assert.assertTrue(result.shouldRetry(HashMap()))
Assert.assertTrue(result.shouldRetry(HashMap(), true))
}

@Test
fun testOversizedFailedRequest() {
val result = RequestResult(500, true, ArrayList())
Assert.assertFalse(result.isSuccessful)
Assert.assertFalse(result.shouldRetry(HashMap()))
Assert.assertFalse(result.shouldRetry(HashMap(), true))
}

@Test
fun testFailedRequestWithNoRetryStatus() {
val result = RequestResult(403, false, ArrayList())
Assert.assertFalse(result.isSuccessful)
Assert.assertFalse(result.shouldRetry(HashMap()))
Assert.assertFalse(result.shouldRetry(HashMap(), true))
}

@Test
Expand All @@ -58,9 +58,16 @@ class RequestResultTest {
customRetry[500] = false
var result = RequestResult(403, false, ArrayList())
Assert.assertFalse(result.isSuccessful)
Assert.assertTrue(result.shouldRetry(customRetry))
Assert.assertTrue(result.shouldRetry(customRetry, true))
result = RequestResult(500, false, ArrayList())
Assert.assertFalse(result.isSuccessful)
Assert.assertFalse(result.shouldRetry(customRetry))
Assert.assertFalse(result.shouldRetry(customRetry, true))
}

@Test
fun testFailedRequestWithDisabledRetry() {
val result = RequestResult(500, false, ArrayList())
Assert.assertFalse(result.isSuccessful)
Assert.assertFalse(result.shouldRetry(HashMap(), false))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,14 @@ class Emitter(context: Context, collectorUri: String, builder: ((Emitter) -> Uni
_customRetryForStatusCodes.set(value ?: HashMap())
}

private val _retryFailedRequests = AtomicReference(EmitterDefaults.retryFailedRequests)
/**
* Whether retrying failed requests is allowed
*/
var retryFailedRequests: Boolean
get() = _retryFailedRequests.get()
set(value) { _retryFailedRequests.set(value) }

/**
* The request headers for the emitter
*/
Expand Down Expand Up @@ -561,7 +569,7 @@ class Emitter(context: Context, collectorUri: String, builder: ((Emitter) -> Uni
if (res.isSuccessful) {
removableEvents.addAll(res.eventIds)
successCount += res.eventIds.size
} else if (res.shouldRetry(customRetryForStatusCodes)) {
} else if (res.shouldRetry(customRetryForStatusCodes, retryFailedRequests)) {
failedWillRetryCount += res.eventIds.size
Logger.e(TAG, "Request sending failed but we will retry later.")
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,11 @@ interface EmitterConfigurationInterface {
* Whether to anonymise server-side user identifiers including the `network_userid` and `user_ipaddress`
*/
var serverAnonymisation: Boolean

/**
* Whether to retry sending events that failed to be sent to the collector.
*
* If disabled, events that failed to be sent will be dropped regardless of other configuration (such as the customRetryForStatusCodes).
*/
var retryFailedRequests: Boolean
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,13 @@ class EmitterControllerImpl(serviceProvider: ServiceProviderInterface) :
emitter.serverAnonymisation = serverAnonymisation
}

override var retryFailedRequests: Boolean
get() = emitter.retryFailedRequests
set(value) {
dirtyConfig.retryFailedRequests = value
emitter.retryFailedRequests = value
}

override val dbCount: Long
get() {
val eventStore = emitter.eventStore
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,6 @@ object EmitterDefaults {
var emitTimeout = 5
var threadPoolSize = 15
var serverAnonymisation = false
var retryFailedRequests = true
var timeUnit = TimeUnit.SECONDS
}
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ class ServiceProvider(
emitter.customRetryForStatusCodes = emitterConfiguration.customRetryForStatusCodes
emitter.serverAnonymisation = emitterConfiguration.serverAnonymisation
emitter.requestHeaders = networkConfiguration.requestHeaders
emitter.retryFailedRequests = emitterConfiguration.retryFailedRequests
}

val emitter = Emitter(context, endpoint, builder)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import org.json.JSONObject
* - threadPoolSize: 15
* - byteLimitGet: 40000 bytes
* - byteLimitPost: 40000 bytes
* - retryFailedRequests: true
*/
open class EmitterConfiguration() : Configuration, EmitterConfigurationInterface {

Expand Down Expand Up @@ -86,6 +87,11 @@ open class EmitterConfiguration() : Configuration, EmitterConfigurationInterface
override var serverAnonymisation: Boolean
get() = _serverAnonymisation ?: sourceConfig?.serverAnonymisation ?: EmitterDefaults.serverAnonymisation
set(value) { _serverAnonymisation = value }

private var _retryFailedRequests: Boolean? = null
override var retryFailedRequests: Boolean
get() = _retryFailedRequests ?: sourceConfig?.retryFailedRequests ?: EmitterDefaults.retryFailedRequests
set(value) { _retryFailedRequests = value }

// Builders

Expand Down Expand Up @@ -168,6 +174,16 @@ open class EmitterConfiguration() : Configuration, EmitterConfigurationInterface
return this
}

/**
* Whether to retry failed requests. By default, this is set to true.
*
* If disabled, events that failed to be sent will be dropped regardless of other configuration (such as the customRetryForStatusCodes).
*/
fun retryFailedRequests(retryFailedRequests: Boolean): EmitterConfiguration {
this.retryFailedRequests = retryFailedRequests
return this
}

// Copyable
override fun copy(): EmitterConfiguration {
return EmitterConfiguration()
Expand All @@ -180,6 +196,7 @@ open class EmitterConfiguration() : Configuration, EmitterConfigurationInterface
.requestCallback(requestCallback)
.customRetryForStatusCodes(customRetryForStatusCodes)
.serverAnonymisation(serverAnonymisation)
.retryFailedRequests(retryFailedRequests)
}

// JSON Formatter
Expand All @@ -205,5 +222,6 @@ open class EmitterConfiguration() : Configuration, EmitterConfigurationInterface
}
_customRetryForStatusCodes = customRetryForStatusCodes
}
if (jsonObject.has("retryFailedRequests")) { _retryFailedRequests = jsonObject.getBoolean("retryFailedRequests") }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,17 @@ class RequestResult(
*
* @see com.snowplowanalytics.snowplow.configuration.EmitterConfiguration.customRetryForStatusCodes
*/
fun shouldRetry(customRetryForStatusCodes: Map<Int, Boolean>?): Boolean {
fun shouldRetry(customRetryForStatusCodes: Map<Int, Boolean>?, retryAllowed: Boolean): Boolean {
// don't retry if successful
if (isSuccessful) {
return false
}

// don't retry if retries are not allowed
if (!retryAllowed) {
return false
}

// don't retry if request is larger than max byte limit
if (oversize) {
return false
Expand Down

0 comments on commit 0605fd0

Please sign in to comment.