Skip to content

Commit 8cb4d51

Browse files
committed
chore(nimbus-sdk): move enrollment status off events ping
1 parent 42c175c commit 8cb4d51

File tree

11 files changed

+141
-74
lines changed

11 files changed

+141
-74
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@
1212
* Added `eval_jexl_debug()` method to `NimbusTargetingHelper` interface for CLI testing and debugging. Evaluates JEXL expressions and returns debug results as JSON. Consumers implementing this interface must add the new method.
1313
([#7156](https://github.com/mozilla/application-services/pull/7156))
1414
([#31607](https://github.com/mozilla-mobile/firefox-ios/pull/31607))
15-
* Update Cirrus metrics handler interface for recording enrollment status to specify nimbus user id as separate metric and change method name from `record_enrollment_statuses` to `record_enrollment_statuses_v2`. Consumers implementing this interface must add the new method.
15+
* Update Cirrus `MetricsHandler` interface for recording enrollment status to specify nimbus user id as separate metric and change method name from `record_enrollment_statuses` to `record_enrollment_statuses_v2`. Consumers implementing this interface must add the new method.
1616
([#14280](https://github.com/mozilla/experimenter/pull/14280))
17+
* Split Nimbus `RecordedContext` interface method `record` into `recordContext` and `submit`, and moved `record_enrollment_statuses` method over from `MetricsHandler` interface. Consumers implementing these interfaces must provide the new methods. ([#14542](https://github.com/mozilla/experimenter/issues/14542))
1718
* Enable using `PreviousGeckoPrefState` to revert Gecko pref experiments when applicable ([#7157](https://github.com/mozilla/application-services/pull/7157))
1819

1920
### Error support

components/nimbus/android/src/main/java/org/mozilla/experiments/nimbus/Nimbus.kt

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ import org.mozilla.experiments.nimbus.internal.AvailableExperiment
3434
import org.mozilla.experiments.nimbus.internal.EnrolledExperiment
3535
import org.mozilla.experiments.nimbus.internal.EnrollmentChangeEvent
3636
import org.mozilla.experiments.nimbus.internal.EnrollmentChangeEventType
37-
import org.mozilla.experiments.nimbus.internal.EnrollmentStatusExtraDef
3837
import org.mozilla.experiments.nimbus.internal.FeatureExposureExtraDef
3938
import org.mozilla.experiments.nimbus.internal.GeckoPrefHandler
4039
import org.mozilla.experiments.nimbus.internal.GeckoPrefState
@@ -92,21 +91,6 @@ open class Nimbus(
9291
private val logger = delegate.logger
9392

9493
private val metricsHandler = object : MetricsHandler {
95-
override fun recordEnrollmentStatuses(enrollmentStatusExtras: List<EnrollmentStatusExtraDef>) {
96-
for (extra in enrollmentStatusExtras) {
97-
NimbusEvents.enrollmentStatus.record(
98-
NimbusEvents.EnrollmentStatusExtra(
99-
branch = extra.branch,
100-
slug = extra.slug,
101-
status = extra.status,
102-
reason = extra.reason,
103-
errorString = extra.errorString,
104-
conflictSlug = extra.conflictSlug,
105-
),
106-
)
107-
}
108-
}
109-
11094
override fun recordFeatureActivation(event: FeatureExposureExtraDef) {
11195
NimbusEvents.activation.record(
11296
NimbusEvents.ActivationExtra(

components/nimbus/android/src/test/java/org/mozilla/experiments/nimbus/NimbusTests.kt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import org.mozilla.experiments.nimbus.GleanMetrics.NimbusEvents
3838
import org.mozilla.experiments.nimbus.GleanMetrics.NimbusHealth
3939
import org.mozilla.experiments.nimbus.internal.EnrollmentChangeEvent
4040
import org.mozilla.experiments.nimbus.internal.EnrollmentChangeEventType
41+
import org.mozilla.experiments.nimbus.internal.EnrollmentStatusExtraDef
4142
import org.mozilla.experiments.nimbus.internal.GeckoPref
4243
import org.mozilla.experiments.nimbus.internal.GeckoPrefHandler
4344
import org.mozilla.experiments.nimbus.internal.GeckoPrefState
@@ -767,10 +768,18 @@ class NimbusTests {
767768
this.eventQueryValues = eventQueryValues
768769
}
769770

770-
override fun record() {
771+
override fun recordContext() {
771772
recorded.add(this.toJson())
772773
}
773774

775+
override fun recordEnrollmentStatuses(enrollmentStatusExtras: List<EnrollmentStatusExtraDef>) {
776+
//
777+
}
778+
779+
override fun submit() {
780+
//
781+
}
782+
774783
override fun toJson(): JsonObject {
775784
val contextToRecord = JSONObject()
776785
contextToRecord.put("enabled", true)

components/nimbus/src/metrics.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,6 @@ use crate::{enrollment::ExperimentEnrollment, EnrolledFeature, EnrollmentStatus}
99
use serde_derive::{Deserialize, Serialize};
1010

1111
pub trait MetricsHandler: Send + Sync {
12-
#[cfg(feature = "stateful")]
13-
fn record_enrollment_statuses(&self, enrollment_status_extras: Vec<EnrollmentStatusExtraDef>);
14-
1512
#[cfg(not(feature = "stateful"))]
1613
fn record_enrollment_statuses_v2(
1714
&self,

components/nimbus/src/nimbus.udl

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@ enum EnrollmentChangeEventType {
8484
};
8585

8686
callback interface MetricsHandler {
87-
void record_enrollment_statuses(sequence<EnrollmentStatusExtraDef> enrollment_status_extras);
8887
/// Feature activation is the pre-cursor to feature exposure: it is defined as the first time
8988
/// the feature configuration is asked for.
9089
void record_feature_activation(FeatureExposureExtraDef event);
@@ -195,7 +194,11 @@ interface RecordedContext {
195194

196195
void set_event_query_values(record<string, f64> event_query_values);
197196

198-
void record();
197+
void record_context();
198+
199+
void record_enrollment_statuses(sequence<EnrollmentStatusExtraDef> enrollment_status_extras);
200+
201+
void submit();
199202
};
200203

201204
interface NimbusClient {

components/nimbus/src/stateful/nimbus_client.rs

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,6 @@ impl NimbusClient {
229229
&coenrolling_ids,
230230
self.gecko_prefs.clone(),
231231
)?;
232-
self.record_enrollment_status_telemetry(state)?;
233232
Ok(())
234233
}
235234

@@ -288,7 +287,9 @@ impl NimbusClient {
288287
let existing_experiments: Vec<Experiment> =
289288
db.get_store(StoreId::Experiments).collect_all(&writer)?;
290289
let events = self.evolve_experiments(db, &mut writer, &mut state, &existing_experiments)?;
291-
self.end_initialize(db, writer, &mut state)?;
290+
let res = self.end_initialize(db, writer, &mut state);
291+
self.record_enrollment_status_telemetry(&mut state)?;
292+
res?;
292293
Ok(events)
293294
}
294295

@@ -304,7 +305,9 @@ impl NimbusClient {
304305
let existing_experiments: Vec<Experiment> =
305306
db.get_store(StoreId::Experiments).collect_all(&writer)?;
306307
let events = self.evolve_experiments(db, &mut writer, &mut state, &existing_experiments)?;
307-
self.end_initialize(db, writer, &mut state)?;
308+
let res = self.end_initialize(db, writer, &mut state);
309+
self.record_enrollment_status_telemetry(&mut state)?;
310+
res?;
308311
Ok(events)
309312
}
310313

@@ -449,7 +452,7 @@ impl NimbusClient {
449452
self.gecko_prefs.clone(),
450453
);
451454
if let Some(ref recorded_context) = self.recorded_context {
452-
recorded_context.record();
455+
recorded_context.record_context();
453456
}
454457
let coenrolling_feature_ids = self
455458
.coenrolling_feature_ids
@@ -475,6 +478,7 @@ impl NimbusClient {
475478
let mut state = self.mutable_state.lock().unwrap();
476479
self.begin_initialize(db, &mut writer, &mut state)?;
477480

481+
let should_record_enrollment_status = pending_updates.is_some();
478482
let res = match pending_updates {
479483
Some(new_experiments) => {
480484
self.update_ta_active_experiments(db, &writer, &mut state)?;
@@ -485,7 +489,12 @@ impl NimbusClient {
485489
};
486490

487491
// Finish up any cleanup, e.g. copying from database in to memory.
488-
self.end_initialize(db, writer, &mut state)?;
492+
let end_init_res = self.end_initialize(db, writer, &mut state);
493+
if should_record_enrollment_status {
494+
self.record_enrollment_status_telemetry(&mut state)?;
495+
}
496+
end_init_res?;
497+
489498
Ok(res)
490499
}
491500

@@ -1003,16 +1012,19 @@ impl NimbusClient {
10031012
})
10041013
.map(|exp| &*exp.slug)
10051014
.collect::<HashSet<&str>>();
1006-
self.metrics_handler.record_enrollment_statuses(
1007-
self.database_cache
1008-
.get_enrollments()?
1009-
.into_iter()
1010-
.filter_map(|e| match experiments.contains(&*e.slug) {
1011-
true => Some(e.into()),
1012-
false => None,
1013-
})
1014-
.collect(),
1015-
);
1015+
let statuses = self
1016+
.database_cache
1017+
.get_enrollments()?
1018+
.into_iter()
1019+
.filter_map(|e| match experiments.contains(&*e.slug) {
1020+
true => Some(e.into()),
1021+
false => None,
1022+
})
1023+
.collect();
1024+
if let Some(ref recorded_context) = self.recorded_context {
1025+
recorded_context.record_enrollment_statuses(statuses);
1026+
recorded_context.submit();
1027+
}
10161028
Ok(())
10171029
}
10181030
}

components/nimbus/src/stateful/targeting.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use crate::{
77
enrollment::ExperimentEnrollment,
88
error::{warn, BehaviorError},
99
json::JsonObject,
10+
metrics::EnrollmentStatusExtraDef,
1011
stateful::behavior::{EventQueryType, EventStore},
1112
NimbusError, NimbusTargetingHelper, Result, TargetingAttributes,
1213
};
@@ -60,7 +61,17 @@ pub trait RecordedContext: Send + Sync {
6061
/// Records the context object to Glean
6162
///
6263
/// This method will be implemented in foreign code, i.e: Kotlin, Swift, Python, etc...
63-
fn record(&self);
64+
fn record_context(&self);
65+
66+
/// Records the enrollment statuses to Glean
67+
///
68+
/// This method will be implemented in foreign code, i.e: Kotlin, Swift, Python, etc...
69+
fn record_enrollment_statuses(&self, enrollment_status_extras: Vec<EnrollmentStatusExtraDef>);
70+
71+
/// Submits the ping for context and enrollment statuses to Glean
72+
///
73+
/// This method will be implemented in foreign code, i.e: Kotlin, Swift, Python, etc...
74+
fn submit(&self);
6475
}
6576

6677
impl dyn RecordedContext {

components/nimbus/src/tests/helpers.rs

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,9 @@ impl Default for NimbusTargetingHelper {
6767
#[derive(Default)]
6868
struct RecordedContextState {
6969
context: Map<String, Value>,
70-
record_calls: u64,
70+
record_context_calls: u64,
71+
enrollment_statuses: Vec<EnrollmentStatusExtraDef>,
72+
submit_calls: u64,
7173
event_queries: HashMap<String, String>,
7274
event_query_values: HashMap<String, f64>,
7375
}
@@ -86,11 +88,26 @@ impl TestRecordedContext {
8688
}
8789
}
8890

89-
pub fn get_record_calls(&self) -> u64 {
91+
pub fn get_record_context_calls(&self) -> u64 {
92+
self.state
93+
.lock()
94+
.expect("could not lock state mutex")
95+
.record_context_calls
96+
}
97+
98+
pub fn get_enrollment_statuses(&self) -> Vec<EnrollmentStatusExtraDef> {
9099
self.state
91100
.lock()
92101
.expect("could not lock state mutex")
93-
.record_calls
102+
.enrollment_statuses
103+
.clone()
104+
}
105+
106+
pub fn get_submit_calls(&self) -> u64 {
107+
self.state
108+
.lock()
109+
.expect("could not lock state mutex")
110+
.submit_calls
94111
}
95112

96113
pub fn set_context(&self, context: Value) {
@@ -141,14 +158,26 @@ impl RecordedContext for TestRecordedContext {
141158
.insert("events".into(), json!(event_query_values));
142159
}
143160

144-
fn record(&self) {
161+
fn record_context(&self) {
162+
let mut state = self.state.lock().expect("could not lock state mutex");
163+
state.record_context_calls += 1;
164+
}
165+
166+
#[cfg(feature = "stateful")]
167+
fn record_enrollment_statuses(&self, enrollment_status_extras: Vec<EnrollmentStatusExtraDef>) {
168+
let mut state = self.state.lock().unwrap();
169+
state.enrollment_statuses.extend(enrollment_status_extras);
170+
}
171+
172+
fn submit(&self) {
145173
let mut state = self.state.lock().expect("could not lock state mutex");
146-
state.record_calls += 1;
174+
state.submit_calls += 1;
147175
}
148176
}
149177

150178
#[derive(Default)]
151179
struct MetricState {
180+
#[cfg(not(feature = "stateful"))]
152181
enrollment_statuses: Vec<EnrollmentStatusExtraDef>,
153182
#[cfg(feature = "stateful")]
154183
activations: Vec<FeatureExposureExtraDef>,
@@ -176,6 +205,7 @@ impl TestMetrics {
176205
}
177206
}
178207

208+
#[cfg(not(feature = "stateful"))]
179209
pub fn get_enrollment_statuses(&self) -> Vec<EnrollmentStatusExtraDef> {
180210
self.state.lock().unwrap().enrollment_statuses.clone()
181211
}
@@ -191,7 +221,6 @@ impl TestMetrics {
191221
pub fn clear(&self) {
192222
let mut state = self.state.lock().unwrap();
193223
state.activations.clear();
194-
state.enrollment_statuses.clear();
195224
state.malformeds.clear();
196225
}
197226

@@ -205,12 +234,6 @@ impl TestMetrics {
205234
}
206235

207236
impl MetricsHandler for TestMetrics {
208-
#[cfg(feature = "stateful")]
209-
fn record_enrollment_statuses(&self, enrollment_status_extras: Vec<EnrollmentStatusExtraDef>) {
210-
let mut state = self.state.lock().unwrap();
211-
state.enrollment_statuses.extend(enrollment_status_extras);
212-
}
213-
214237
#[cfg(not(feature = "stateful"))]
215238
fn record_enrollment_statuses_v2(
216239
&self,

0 commit comments

Comments
 (0)