10

我们使用的是 Firebase iOS 框架 (5.9.0) 的当前版本,在尝试运行具有激活事件的 A/B 测试实验时遇到了一个奇怪的问题。

由于我们想在首次启动时运行实验,因此我们在应用程序启动时有一个自定义启动画面,我们会在获取远程配置时显示该启动画面。获取完成后,我们立即激活获取的配置,然后检查我们是否收到有关实验参与的信息以适当地重新配置下一个 UI。在我们确定当前实例实际上应该是测试的一部分之前,还需要进行额外的检查,从而确定激活事件。基本上,代码如下所示:

<code that shows splash>

…

[[FIRRemoteConfig remoteConfig] fetchWithExpirationDuration:7 completionHandler:^(FIRRemoteConfigFetchStatus status, NSError * _Nullable error) {

    [[FIRRemoteConfig remoteConfig] activateFetched];

    if (<checks that see if we received info about being selected to participate in the experiment and if local conditions are met for experiment participation>) {

        [FIRAnalytics logEventWithName:@"RegistrationEntryExperimentActivation" parameters:nil];

        <dismiss splash screen and show next UI screen based on experiment variation received in remote config>
    } else {
        <dismiss splash screen and show next UI screen>
    }
}

使用上述方法(这是完全直截了当的 IMO)无法正常工作。在启用调试器和 Firebase 日志记录之后,我可以在日志中看到发生了竞态条件问题。基本上,FirebaseactivateFetched()调用不会在 activateFetched 调用中同步设置“条件用户属性实验 ID”,而是在稍后的短时间内设置它。因此,我们在 activateFetched 之后立即触发激活事件不会触发此条件用户属性,并且后续的实验漏斗/目标事件未正确标记为实验的一部分(实验甚至一开始都没有被激活)。

如果我们更改代码以将激活事件的发送延迟一些任意延迟:

<code that shows splash>

…

[[FIRRemoteConfig remoteConfig] fetchWithExpirationDuration:7 completionHandler:^(FIRRemoteConfigFetchStatus status, NSError * _Nullable error) {

    [[FIRRemoteConfig remoteConfig] activateFetched];

    if (<checks that see if we received info about being selected to participate in the experiment and if local conditions are met for experiment participation>) {

        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

            [FIRAnalytics logEventWithName:@"RegistrationEntryExperimentActivation" parameters:nil];

            <dismiss splash screen and show next UI screen based on experiment variation received in remote config>
        }
    } else {
        <dismiss splash screen and show next UI screen>
    }
}

实验的条件用户属性预先正确设置并由事件触发(导致实验激活和后续事件被正确标记为实验的一部分)。

现在,这段代码显然很丑陋并且容易出现可能的竞争条件。0.5 秒的延迟保守地设置为希望在所有 iOS 设备上都足够了,但¯_(ツ)_/¯。我已经多次阅读了可用的文档,并尝试查看所有可用的 API 方法,但没有成功确定开始发送事件的正确点应该是什么。如果该activateFetched方法使用重新配置内部对象的异步过程,那么人们会期望一个回调方法,该方法向调用者指示所有重新配置完成并准备好供应用程序进一步使用的时间点。似乎框架工程师没有预料到有人需要在远程配置文件激活后立即发送激活事件的用例……</p>

有没有其他人遇到过这个问题?我们是否遗漏了 API 中的某些内容?有没有更聪明的方法来activateFetched完成它的事情?

希望一些 Firebase 工程师也能用他们的智慧加入:)

谢谢

4

0 回答 0