Skip to content

Commit dcbd7ba

Browse files
authored
PIR: Implement pixels for breakage KPIs (#7108)
Task/Issue URL: https://app.asana.com/1/137249556945/project/72649045549333/task/1211848227486283?focus=true ### Description See attached task description ### Steps to test this PR https://app.asana.com/1/137249556945/project/72649045549333/task/1211863510648442?focus=true
1 parent 30df5b0 commit dcbd7ba

File tree

18 files changed

+1323
-226
lines changed

18 files changed

+1323
-226
lines changed

PixelDefinitions/pixels/personal_information_removal.json5

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,5 +148,117 @@
148148
"type": "string"
149149
}
150150
]
151+
},
152+
"dbp_optoutjob_at-7-days_confirmed": {
153+
"description": "Pixel that contains if any submitted opt-out has been confirmed 7 days after submission.",
154+
"owners": ["karlenDimla", "landomen"],
155+
"triggers": ["other"],
156+
"suffixes": ["form_factor"],
157+
"parameters": [
158+
"appVersion",
159+
{
160+
"key": "data_broker",
161+
"description": "The URL of the data broker that has a confirmed opt-out after 7 days",
162+
"type": "string"
163+
}
164+
]
165+
},
166+
"dbp_optoutjob_at-7-days_unconfirmed": {
167+
"description": "Pixel that contains if any submitted opt-out are still unconfirmed 7 days after submission.",
168+
"owners": ["karlenDimla", "landomen"],
169+
"triggers": ["other"],
170+
"suffixes": ["form_factor"],
171+
"parameters": [
172+
"appVersion",
173+
{
174+
"key": "data_broker",
175+
"description": "The URL of the data broker that has an unconfirmed opt-out after 7 days",
176+
"type": "string"
177+
}
178+
]
179+
},
180+
"dbp_optoutjob_at-14-days_confirmed": {
181+
"description": "Pixel that contains if any submitted opt-out has been confirmed 14 days after submission.",
182+
"owners": ["karlenDimla", "landomen"],
183+
"triggers": ["other"],
184+
"suffixes": ["form_factor"],
185+
"parameters": [
186+
"appVersion",
187+
{
188+
"key": "data_broker",
189+
"description": "The URL of the data broker that has a confirmed opt-out after 14 days",
190+
"type": "string"
191+
}
192+
]
193+
},
194+
"dbp_optoutjob_at-14-days_unconfirmed": {
195+
"description": "Pixel that contains if any submitted opt-out are still unconfirmed 14 days after submission.",
196+
"owners": ["karlenDimla", "landomen"],
197+
"triggers": ["other"],
198+
"suffixes": ["form_factor"],
199+
"parameters": [
200+
"appVersion",
201+
{
202+
"key": "data_broker",
203+
"description": "The URL of the data broker that has an unconfirmed opt-out after 14 days",
204+
"type": "string"
205+
}
206+
]
207+
},
208+
"dbp_optoutjob_at-21-days_confirmed": {
209+
"description": "Pixel that contains if any submitted opt-out has been confirmed 21 days after submission.",
210+
"owners": ["karlenDimla", "landomen"],
211+
"triggers": ["other"],
212+
"suffixes": ["form_factor"],
213+
"parameters": [
214+
"appVersion",
215+
{
216+
"key": "data_broker",
217+
"description": "The URL of the data broker that has a confirmed opt-out after 21 days",
218+
"type": "string"
219+
}
220+
]
221+
},
222+
"dbp_optoutjob_at-21-days_unconfirmed": {
223+
"description": "Pixel that contains if any submitted opt-out are still unconfirmed 21 days after submission.",
224+
"owners": ["karlenDimla", "landomen"],
225+
"triggers": ["other"],
226+
"suffixes": ["form_factor"],
227+
"parameters": [
228+
"appVersion",
229+
{
230+
"key": "data_broker",
231+
"description": "The URL of the data broker that has an unconfirmed opt-out after 21 days",
232+
"type": "string"
233+
}
234+
]
235+
},
236+
"dbp_optoutjob_at-42-days_confirmed": {
237+
"description": "Pixel that contains if any submitted opt-out has been confirmed 42 days after submission.",
238+
"owners": ["karlenDimla", "landomen"],
239+
"triggers": ["other"],
240+
"suffixes": ["form_factor"],
241+
"parameters": [
242+
"appVersion",
243+
{
244+
"key": "data_broker",
245+
"description": "The URL of the data broker that has a confirmed opt-out after 42 days",
246+
"type": "string"
247+
}
248+
]
249+
},
250+
"dbp_optoutjob_at-42-days_unconfirmed": {
251+
"description": "Pixel that contains if any submitted opt-out are still unconfirmed 42 days after submission.",
252+
"owners": ["karlenDimla", "landomen"],
253+
"triggers": ["other"],
254+
"suffixes": ["form_factor"],
255+
"parameters": [
256+
"appVersion",
257+
{
258+
"key": "data_broker",
259+
"description": "The URL of the data broker that has an unconfirmed opt-out after 42 days",
260+
"type": "string"
261+
}
262+
]
151263
}
152264
}

pir/pir-impl/schemas/com.duckduckgo.pir.impl.store.PirDatabase/15.json

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"formatVersion": 1,
33
"database": {
44
"version": 15,
5-
"identityHash": "584648b8b3065521786fb33f44214f2e",
5+
"identityHash": "a5782d19654dee4cad932b458037bb37",
66
"entities": [
77
{
88
"tableName": "pir_broker_json_etag",
@@ -696,7 +696,7 @@
696696
},
697697
{
698698
"tableName": "pir_optout_job_record",
699-
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`extractedProfileId` INTEGER NOT NULL, `brokerName` TEXT NOT NULL, `userProfileId` INTEGER NOT NULL, `status` TEXT NOT NULL, `attemptCount` INTEGER NOT NULL, `lastOptOutAttemptDate` INTEGER, `optOutRequestedDate` INTEGER NOT NULL, `optOutRemovedDate` INTEGER NOT NULL, `deprecated` INTEGER NOT NULL, `dateCreatedInMillis` INTEGER NOT NULL, PRIMARY KEY(`extractedProfileId`))",
699+
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`extractedProfileId` INTEGER NOT NULL, `brokerName` TEXT NOT NULL, `userProfileId` INTEGER NOT NULL, `status` TEXT NOT NULL, `attemptCount` INTEGER NOT NULL, `lastOptOutAttemptDate` INTEGER, `optOutRequestedDate` INTEGER NOT NULL, `optOutRemovedDate` INTEGER NOT NULL, `deprecated` INTEGER NOT NULL, `dateCreatedInMillis` INTEGER NOT NULL, `reporting_sevenDayConfirmationReportSentDateMs` INTEGER NOT NULL, `reporting_fourteenDayConfirmationReportSentDateMs` INTEGER NOT NULL, `reporting_twentyOneDayConfirmationReportSentDateMs` INTEGER NOT NULL, `reporting_fortyTwoDayConfirmationReportSentDateMs` INTEGER NOT NULL, PRIMARY KEY(`extractedProfileId`))",
700700
"fields": [
701701
{
702702
"fieldPath": "extractedProfileId",
@@ -757,6 +757,30 @@
757757
"columnName": "dateCreatedInMillis",
758758
"affinity": "INTEGER",
759759
"notNull": true
760+
},
761+
{
762+
"fieldPath": "reporting.sevenDayConfirmationReportSentDateMs",
763+
"columnName": "reporting_sevenDayConfirmationReportSentDateMs",
764+
"affinity": "INTEGER",
765+
"notNull": true
766+
},
767+
{
768+
"fieldPath": "reporting.fourteenDayConfirmationReportSentDateMs",
769+
"columnName": "reporting_fourteenDayConfirmationReportSentDateMs",
770+
"affinity": "INTEGER",
771+
"notNull": true
772+
},
773+
{
774+
"fieldPath": "reporting.twentyOneDayConfirmationReportSentDateMs",
775+
"columnName": "reporting_twentyOneDayConfirmationReportSentDateMs",
776+
"affinity": "INTEGER",
777+
"notNull": true
778+
},
779+
{
780+
"fieldPath": "reporting.fortyTwoDayConfirmationReportSentDateMs",
781+
"columnName": "reporting_fortyTwoDayConfirmationReportSentDateMs",
782+
"affinity": "INTEGER",
783+
"notNull": true
760784
}
761785
],
762786
"primaryKey": {
@@ -946,7 +970,7 @@
946970
"views": [],
947971
"setupQueries": [
948972
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
949-
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '584648b8b3065521786fb33f44214f2e')"
973+
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'a5782d19654dee4cad932b458037bb37')"
950974
]
951975
}
952976
}

pir/pir-impl/src/main/java/com/duckduckgo/pir/impl/common/PirJobConstants.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,5 @@ object PirJobConstants {
2222
const val MAX_DETACHED_WEBVIEW_COUNT = 20
2323
const val SCHEDULED_SCAN_INTERVAL_HOURS = 12L
2424
const val EMAIL_CONFIRMATION_INTERVAL_HOURS = 8L
25+
const val CUSTOM_PIXEL_INTERVAL_HOURS = 5L
2526
}

pir/pir-impl/src/main/java/com/duckduckgo/pir/impl/models/scheduling/JobRecord.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ sealed class JobRecord(
5656
val optOutRemovedDateInMillis: Long = 0L,
5757
val deprecated: Boolean = false,
5858
val dateCreatedInMillis: Long = 0L,
59+
val confirmation7dayReportSentDateMs: Long = 0L,
60+
val confirmation14dayReportSentDateMs: Long = 0L,
61+
val confirmation21dayReportSentDateMs: Long = 0L,
62+
val confirmation42dayReportSentDateMs: Long = 0L,
5963
) : JobRecord(brokerName, userProfileId) {
6064
enum class OptOutJobStatus {
6165
/** Opt-out has not been executed yet and should be executed when possible */

pir/pir-impl/src/main/java/com/duckduckgo/pir/impl/pixels/OptOut24HourSubmissionSuccessRateReporter.kt

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,13 @@
1717
package com.duckduckgo.pir.impl.pixels
1818

1919
import com.duckduckgo.common.utils.CurrentTimeProvider
20+
import com.duckduckgo.common.utils.DispatcherProvider
2021
import com.duckduckgo.di.scopes.AppScope
2122
import com.duckduckgo.pir.impl.store.PirRepository
23+
import com.duckduckgo.pir.impl.store.PirSchedulingRepository
2224
import com.squareup.anvil.annotations.ContributesBinding
25+
import kotlinx.coroutines.withContext
26+
import logcat.logcat
2327
import java.util.concurrent.TimeUnit
2428
import javax.inject.Inject
2529
import kotlin.math.abs
@@ -34,32 +38,44 @@ class RealOptOut24HourSubmissionSuccessRateReporter @Inject constructor(
3438
private val pirRepository: PirRepository,
3539
private val currentTimeProvider: CurrentTimeProvider,
3640
private val pirPixelSender: PirPixelSender,
41+
private val pirSchedulingRepository: PirSchedulingRepository,
42+
private val dispatcherProvider: DispatcherProvider,
3743
) : OptOut24HourSubmissionSuccessRateReporter {
3844
override suspend fun attemptFirePixel() {
39-
val startDate = pirRepository.getCustomStatsPixelsLastSentMs()
40-
val now = currentTimeProvider.currentTimeMillis()
45+
withContext(dispatcherProvider.io()) {
46+
logcat { "PIR-CUSTOM-STATS: Attempt to fire 24hour submission pixels" }
47+
val startDate = pirRepository.getCustomStatsPixelsLastSentMs()
48+
val now = currentTimeProvider.currentTimeMillis()
4149

42-
if (shouldFirePixel(startDate, now)) {
50+
if (!shouldFirePixel(startDate, now)) return@withContext
51+
logcat { "PIR-CUSTOM-STATS: Should fire pixel - 24hrs passed since last send" }
4352
val endDate = now - TimeUnit.HOURS.toMillis(24)
4453
val activeBrokers = pirRepository.getAllActiveBrokerObjects()
4554
val hasUserProfiles = pirRepository.getAllUserProfileQueries().isNotEmpty()
55+
val activeOptOutJobRecords = pirSchedulingRepository.getAllValidOptOutJobRecords()
56+
57+
if (activeBrokers.isNotEmpty() && activeOptOutJobRecords.isNotEmpty() && hasUserProfiles) {
58+
activeBrokers.forEach { broker ->
59+
val activeJobRecordsForBroker = activeOptOutJobRecords.filter { it.brokerName == broker.name }
60+
61+
if (activeJobRecordsForBroker.isEmpty()) return@forEach
4662

47-
if (activeBrokers.isNotEmpty() && hasUserProfiles) {
48-
activeBrokers.forEach {
4963
val successRate = optOutSubmitRateCalculator.calculateOptOutSubmitRate(
50-
it.name,
64+
activeJobRecordsForBroker,
5165
startDate,
5266
endDate,
5367
)
5468

69+
logcat { "PIR-CUSTOM-STATS: 24hr submission ${broker.name} : $successRate" }
5570
if (successRate != null) {
5671
pirPixelSender.reportBrokerCustomStateOptOutSubmitRate(
57-
brokerUrl = it.url,
72+
brokerUrl = broker.url,
5873
optOutSuccessRate = successRate,
5974
)
6075
}
6176
}
6277

78+
logcat { "PIR-CUSTOM-STATS: Updating last send date to $endDate" }
6379
pirRepository.setCustomStatsPixelsLastSentMs(endDate)
6480
}
6581
}

0 commit comments

Comments
 (0)