Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

OFREP ETag can result in race condition weakness.

未关闭
#83 0 条评论 1 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

评估

难度
5/5
预计耗时
一周以上
新手友好度
30/100
Issue 类型
功能
描述清晰度
需要澄清
活跃度
冷清
领域
api

调研方向

首先阅读批量评估端点的 OFREP 规范及其当前的 ETag 缓存失效行为。当规范对 LastModified 标头的处理方式作出决定并完成文档记录,包括其与连续配置更改和条件请求的关系时,该提案即告完成。

由索引模型根据 Issue 内容生成。

描述

Problem

By using the ETag as the cache differentiator, you can run into some ugly consequences based on the reliability/consistency of your underlying datastore. This is not specific to any one implementation or another.

Detail

ETag just assigns whether or not the value has changed since the last request, and has no bearing on when, or the order of what lifecycle operation configs have been changed. This can have major impacts, as illustrated later on.

Below is a sample progression of the versions of a single configuration that were made extremely close together. In this case, each configuration is different (hence the different ETags) and was updated in sequence.

flowchart LR

CN[Config 0<br/>ETag=Z]
C1[Config 1<br/>ETag=A]
C2[Config 2<br/>ETag=B]
C3[Config 3<br/>ETag=C]
CP[Config N...]

CN -->|T=-2...| C1
C1 -->|T=0.1| C2
C2 -->|T=0.2| C3
C3 -->|T=0.3| CP

This update process means that you are relying on your backing datastore to be guaranteed to write the configurations in order, every time, and ensure that there are no out of order writes.

If there are out of order writes (or another race condition in something persay the cache filling, etc) you may get an unknown final configuration at T=0.5.

For the purposes of this, the reason (SSE, Polling, etc) for the given refetches is irrelevant as they're a complexity that can make this problem worse, or better depending on vendor implementation. The OFREP spec does not define how these messages should be handled/sent out based on multiple changes to the underlying configuration, and thus we cannot speculate on a given design.

Example Issues

Example 1 - Not an issue

Let's pose a situation here with the following criteria:

  • An OFREP provider has been initialized with Config 0, an arbitrary configuration before the series of edits here, with an ETag of Z.
  • There was a race condition in the underlying store for the configuration, and the configuration being served is Config 2 incorrectly.
  • The OFREP provider makes a fetch to retrieve the current config at T=0.35 sending the If-None-Match=Z and retrieves Config 2.

This results in the provider comparing the ETags and validating them to be different, and accepting Config 2 as the valid config. For all intents and purposes to the provider, this is accurate and has no issues. But this means the provider has missed the latest available update. Not the fault of OFREP here.

Example 2 - Unintended Rollback of the config

Let's add a small modification to this:

  • An OFREP provider has been initialized with Config 2, as it initialized/fetched the config at the exact moment it was written, with an ETag of B.
  • There was a race condition in the underlying store for the configuration, and shortly after initialization the final config written resulted in being Config 1.

This has a much more drastic impact. To the provider, we're now invalidating the current configuration with an invalid out of date one. But because the ETag is "different" there is no reason to suspect/reject the configuration.

The reality here, is that the configuration was rolled back in time, with potentially unknown impact based on the usage/plan to roll out the config.

Proposed Solution - LastModified Headers

By introducing the LastModified Header as an optional/equally valid cache invalidation header option, you now add the timestamp of the originating file/change to the validation path.

Let's revisit the previous situations but with the concept of validating against a LastModified Header.

flowchart LR

CN[Config 0<br/>LastModified=T<br/>ETag=Z]
C1[Config 1<br/>LastModified=T+0.1<br/>ETag=A]
C2[Config 2<br/>LastModified=T+0.2<br/>ETag=B]
C3[Config 3<br/>LastModified=T+0.3<br/>ETag=C]
CP[Config N...]

CN -->|T=-2...| C1
C1 -->|T=0.1| C2
C2 -->|T=0.2| C3
C3 -->|T=0.3| CP

Example 1 - Not an issue

Let's pose a situation here with the following criteria:

  • An OFREP provider has been initialized with Config 0, an arbitrary configuration before the series of edits here, with a LastModified of T.
  • The OFREP provider makes a fetch to retrieve the current config at T=0.35 with a If-Modified-Since=T header and retrieves Config 2
  • There was a race condition in the underlying store for the configuration, and the configuration being served is Config 2 incorrectly

This is valid, and does not drastically impact differently than the ETag situation.

Example 2 - Unintended Rollback of the config

  • An OFREP provider has been initialized with Config 2, as it initialized/fetched the config at the exact moment it was written, with a LastModified of T+0.2.
  • There was a race condition in the underlying store for the configuration, and shortly after initialization the final config written resulted in being Config 1.
  • The provider fetches for the configuration with an If-Modified-Since=T+0.2 header and receives a 304, and does not update the config.

Proposal

This ultimately is a safer, and more stable way of returning configuration which at its core is naturally a timeseries based datatype.
The recommendation here is to expand the OFREP spec to make the LastModified header an equally valid cache invalidation header to the bulk evaluation endpoint.

This is a defense in depth approach, and is something very real that I've personally had to deal with and solve for with the DevCycle SDKs and Cloudflare's cache not properly being globally invalidated in time when relating to successive changes.

主要语言
没有语言数据
星标
57
派生
7
平均合并
23 小时 3 分钟
30 天内合并 PR
1

环境准备

  • 没有 Dockerfile 或 Docker Compose 文件
  • 没有 Pull Request 模板
  • 阅读贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

open-feature/protocol 的其他 Issue

查看 open-feature/protocol 的全部 Issue

相似的 Issue

更多 Backend & API Design Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。