in components/nimbus/src/enrollment.rs [185:315]
fn on_experiment_updated(
&self,
is_user_participating: bool,
available_randomization_units: &AvailableRandomizationUnits,
updated_experiment: &Experiment,
targeting_helper: &NimbusTargetingHelper,
out_enrollment_events: &mut Vec<EnrollmentChangeEvent>,
) -> Result<Self> {
Ok(match &self.status {
EnrollmentStatus::NotEnrolled { .. } | EnrollmentStatus::Error { .. } => {
if !is_user_participating || updated_experiment.is_enrollment_paused {
self.clone()
} else {
let updated_enrollment = evaluate_enrollment(
available_randomization_units,
updated_experiment,
targeting_helper,
)?;
log::debug!(
"Experiment '{}' with enrollment {:?} is now {:?}",
&self.slug,
&self,
updated_enrollment
);
if matches!(updated_enrollment.status, EnrollmentStatus::Enrolled { .. }) {
out_enrollment_events.push(updated_enrollment.get_change_event());
}
updated_enrollment
}
}
EnrollmentStatus::Enrolled {
ref branch,
ref reason,
..
} => {
if !is_user_participating {
log::debug!(
"Existing experiment enrollment '{}' is now disqualified (global opt-out)",
&self.slug
);
let updated_enrollment =
self.disqualify_from_enrolled(DisqualifiedReason::OptOut);
out_enrollment_events.push(updated_enrollment.get_change_event());
updated_enrollment
} else if !updated_experiment.has_branch(branch) {
// The branch we were in disappeared!
let updated_enrollment =
self.disqualify_from_enrolled(DisqualifiedReason::Error);
out_enrollment_events.push(updated_enrollment.get_change_event());
updated_enrollment
} else if matches!(reason, EnrolledReason::OptIn) {
// we check if we opted-in an experiment, if so
// we don't need to update our enrollment
self.clone()
} else {
let evaluated_enrollment = evaluate_enrollment(
available_randomization_units,
updated_experiment,
targeting_helper,
)?;
match evaluated_enrollment.status {
EnrollmentStatus::Error { .. } => {
let updated_enrollment =
self.disqualify_from_enrolled(DisqualifiedReason::Error);
out_enrollment_events.push(updated_enrollment.get_change_event());
updated_enrollment
}
EnrollmentStatus::NotEnrolled {
reason: NotEnrolledReason::NotTargeted,
} => {
log::debug!("Existing experiment enrollment '{}' is now disqualified (targeting change)", &self.slug);
let updated_enrollment =
self.disqualify_from_enrolled(DisqualifiedReason::NotTargeted);
out_enrollment_events.push(updated_enrollment.get_change_event());
updated_enrollment
}
EnrollmentStatus::NotEnrolled {
reason: NotEnrolledReason::NotSelected,
} => {
// In the case of a rollout being scaled back, we should be disqualified with NotSelected.
//
let updated_enrollment =
self.disqualify_from_enrolled(DisqualifiedReason::NotSelected);
out_enrollment_events.push(updated_enrollment.get_change_event());
updated_enrollment
}
EnrollmentStatus::NotEnrolled { .. }
| EnrollmentStatus::Enrolled { .. }
| EnrollmentStatus::Disqualified { .. }
| EnrollmentStatus::WasEnrolled { .. } => self.clone(),
}
}
}
EnrollmentStatus::Disqualified {
ref branch, reason, ..
} => {
if !is_user_participating {
log::debug!(
"Disqualified experiment enrollment '{}' has been reset to not-enrolled (global opt-out)",
&self.slug
);
Self {
slug: self.slug.clone(),
status: EnrollmentStatus::Disqualified {
reason: DisqualifiedReason::OptOut,
branch: branch.clone(),
},
}
} else if updated_experiment.is_rollout
&& matches!(
reason,
DisqualifiedReason::NotSelected | DisqualifiedReason::NotTargeted,
)
{
let evaluated_enrollment = evaluate_enrollment(
available_randomization_units,
updated_experiment,
targeting_helper,
)?;
match evaluated_enrollment.status {
EnrollmentStatus::Enrolled { .. } => evaluated_enrollment,
_ => self.clone(),
}
} else {
self.clone()
}
}
EnrollmentStatus::WasEnrolled { .. } => self.clone(),
})
}