Skip to content

feat: added ConfigChanged webhook event for config mutation notifications#877

Open
sauraww wants to merge 1 commit intomainfrom
feat/config-change-webhook-event
Open

feat: added ConfigChanged webhook event for config mutation notifications#877
sauraww wants to merge 1 commit intomainfrom
feat/config-change-webhook-event

Conversation

@sauraww
Copy link
Collaborator

@sauraww sauraww commented Feb 12, 2026

Added ConfigChanged webhook event for cache invalidation

Introduces a new ConfigChanged webhook event type that fires whenever a config version is created — i.e., on any mutation to contexts, default configs, or dimensions.

Motivation

Downstream consumers (e.g., Lambda functions) need to be notified when configuration changes occur so they can invalidate caches scoped to a specific workspace and organisation.

Changes

  • New ConfigChanged variant added to WebhookEvent enum
  • New trigger_config_changed_webhook helper — async function that fires the webhook after DB transaction commits
  • add_config_version remains synchronous — called inside transactions; webhook dispatch happens after commit
  • All 12 config mutation handlers now trigger the webhook:
    • Context: create, update, move, delete, bulk operations, weight recompute
    • Default Config: create, update, delete
    • Dimension: create, update, delete
  • Webhook payload includes change_reason (from the request) and config_version
  • Webhook failure returns HTTP 512 to the caller (consistent with experiment webhook behavior); the DB mutation is always committed regardless

Webhook payload

{
  "event_info": {
    "webhook_event": "ConfigChanged",
    "workspace_id": "...",
    "organisation_id": "...",
    "config_version": "..."
  },
  "payload": {
    "change_reason": "...",
    "config_version": 1234567890
  }
}

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **New Features**
  * Configuration changes now trigger webhook notifications, enabling real-time integration with external systems when configurations are created, updated, deleted, or modified in bulk.

* **Chores**
  * Refactored internal header construction logic for improved consistency and maintainability across modules.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

@sauraww sauraww requested a review from a team as a code owner February 12, 2026 17:34
@semanticdiff-com
Copy link

semanticdiff-com bot commented Feb 12, 2026

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 12, 2026

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

This PR introduces webhook notifications for configuration changes across multiple handlers in the context-aware config API. When configurations are created, updated, deleted, or bulk-operated, a new webhook trigger function is invoked to notify external listeners. The implementation centralizes header construction logic into service utilities and adds serialization support to core types.

Changes

Cohort / File(s) Summary
Webhook Trigger Integration
crates/context_aware_config/src/api/context/handlers.rs, crates/context_aware_config/src/api/default_config/handlers.rs, crates/context_aware_config/src/api/dimension/handlers.rs
Added trigger_config_changed_webhook calls after create, update, delete, and bulk operations. HTTP responses now conditionally return success or error status (512) based on webhook invocation result. Webhook change reason derived from request or operation type.
Webhook Infrastructure
crates/context_aware_config/src/helpers.rs, crates/superposition_types/src/database/models/others.rs
Introduced new trigger_config_changed_webhook function that discovers and invokes ConfigChanged webhook listeners. Added ConfigChanged variant to WebhookEvent enum. Extended ConfigVersion with config_hash field.
Header Construction Refactor
crates/experimentation_platform/src/api/experiments/cac_api.rs, crates/experimentation_platform/src/api/experiments/handlers.rs, crates/experimentation_platform/src/api/experiments/helpers.rs
Moved construct_header_map to centralized location in service_utils; updated all call sites to pass WorkspaceContext instead of separate workspace/org IDs. Removed local fetch_webhook_by_event duplicate from experiments module.
Service Utilities Enhancement
crates/service_utils/src/helpers.rs, crates/service_utils/src/service/types.rs, crates/service_utils/Cargo.toml
Added construct_header_map and fetch_webhook_by_event functions. Extended WorkspaceId, OrganisationId, SchemaName, and WorkspaceContext with Serialize/Deserialize derives. Added actix-http dependency.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Handler as Config Handler
    participant DB as Database
    participant Webhook as Webhook Service
    participant External as External Listener
    participant Redis as Redis Cache

    Client->>Handler: POST/PUT/DELETE config
    Handler->>DB: Perform config operation
    DB-->>Handler: Operation result
    Handler->>Redis: Update cache (optional)
    Redis-->>Handler: Cache updated
    Handler->>Webhook: trigger_config_changed_webhook()
    Webhook->>DB: Lookup ConfigChanged webhook
    DB-->>Webhook: Webhook endpoint
    Webhook->>External: POST webhook notification
    External-->>Webhook: Response
    Webhook-->>Handler: webhook_status (true/false)
    Handler->>Client: HTTP 200/512 based on webhook_status
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • feat: AuthZ setup #543 — Modifies the same handler modules (context, default_config, dimension) with overlapping handler function updates, indicating parallel or interdependent changes to the same code paths.

Suggested labels

enhancement, P1

Suggested reviewers

  • knutties
  • Datron
  • mahatoankitkumar

Poem

🐰 Config changes now sing to the webhook choir,
A notification dance, reaching ever higher!
Handlers coordinate, Redis stays true,
When mutations occur, listeners hear the news too. 🎵

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and accurately describes the main change: introducing a new ConfigChanged webhook event for notifying on config mutations.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/config-change-webhook-event

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@crates/context_aware_config/src/api/default_config/handlers.rs`:
- Around line 565-585: The delete handler currently calls
trigger_config_changed_webhook and only logs when webhook_status is false, then
continues to return 204; change it to mirror create/update behavior by returning
an error response when the webhook call fails: after calling
trigger_config_changed_webhook (the webhook_status boolean), if webhook_status
is false return the same 512-style error response used by create/update handlers
instead of just logging. Update the control flow around
trigger_config_changed_webhook in the delete path (references:
trigger_config_changed_webhook, webhook_status, the delete handler that
currently returns 204) so webhook failures propagate to the client consistently.

In `@crates/context_aware_config/src/helpers.rs`:
- Around line 249-283: In trigger_config_changed_webhook, treat a failed
fetch_webhook_by_event as a failure instead of success: when
fetch_webhook_by_event returns Err, log the error (use the project logger
available in AppState or tracing::error) and return false rather than true so
callers receive the correct failure semantics; keep the successful path that
calls execute_webhook_call(...) for the Ok case and ensure the log message
references WebhookEvent::ConfigChanged and the version_id to aid debugging.
🧹 Nitpick comments (5)
crates/service_utils/Cargo.toml (1)

11-11: Nit: inconsistent brace spacing.

Other workspace dependencies in this file use { workspace = true } (with inner spaces), but this line omits them.

-actix-http = {workspace = true}
+actix-http = { workspace = true }
crates/context_aware_config/src/helpers.rs (1)

219-246: Make config_hash deterministic across runs.
json_config.to_string() can serialize HashMap-backed fields in nondeterministic key order, which can yield different hashes for identical configs. If this hash is used for change detection/deduping, consider canonical JSON (sorted keys) or ordered maps before hashing.

crates/context_aware_config/src/api/context/handlers.rs (3)

141-159: Consider extracting the repeated webhook-trigger + status-code-512 pattern into a helper.

This exact block — call trigger_config_changed_webhook, then branch on the result to build either HttpResponse::Ok() or HttpResponse::build(512) — is duplicated verbatim across all six mutation handlers (create, update, move, delete, bulk, weight_recompute). A small helper returning an HttpResponseBuilder would eliminate ~100 lines of duplication.

Sketch of a possible helper
// In crate helpers or at the top of this module:
async fn trigger_webhook_and_build_response(
    version_id: i64,
    workspace_context: &WorkspaceContext,
    state: &Data<AppState>,
    conn: &mut DBConnection,
    user: &User,
    change_reason: &str,
) -> HttpResponseBuilder {
    let ok = trigger_config_changed_webhook(
        version_id, workspace_context, state, conn, user, change_reason,
    )
    .await;
    if ok {
        HttpResponse::Ok()
    } else {
        HttpResponse::build(
            actix_web::http::StatusCode::from_u16(512)
                .unwrap_or(actix_web::http::StatusCode::INTERNAL_SERVER_ERROR),
        )
    }
}

579-580: Duplicated "Deleted context by" format string.

Line 567 already constructs format!("Deleted context by {}", user.username) for the description inside the transaction. Line 580 rebuilds the same string for the webhook. Consider computing it once before the transaction and reusing it for both.

Proposed fix
+    let delete_reason = format!("Deleted context by {}", user.username);
     let version_id =
         db_conn.transaction::<_, superposition::AppError, _>(|transaction_conn| {
             // ...
             let config_version_desc =
-                Description::try_from(format!("Deleted context by {}", user.username))
+                Description::try_from(delete_reason.clone())
                     .map_err(|e| unexpected_error!(e))?;
             // ...
         })?;
 
     let DbConnection(mut conn) = db_conn;
-    let webhook_change_reason = format!("Deleted context by {}", user.username);
+    let webhook_change_reason = delete_reason;

595-609: Ordering inconsistency: in delete_handler, the response builder is constructed after the Redis update, unlike other handlers.

In create/update/move/bulk/weight_recompute, the pattern is: webhook → build response → redis → return. Here it's: webhook → redis → build response → return. This works but is inconsistent and could confuse future readers. Consider reordering to match the other handlers for uniformity.

Comment on lines 565 to 585
let webhook_status = trigger_config_changed_webhook(
version_id,
&workspace_context,
&state,
&mut conn,
&user,
&format!(
"Default config key '{}' deleted by {}",
key,
user.get_email()
),
)
.await;

if !webhook_status {
log::warn!(
"ConfigChanged webhook failed for workspace: {}",
workspace_context.settings.workspace_name
);
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Webhook failure doesn’t affect delete response.
Create/update return 512 on webhook failure; delete only logs and still returns 204, which hides webhook failures and diverges from the stated behavior.

🛠️ Suggested fix
             if !webhook_status {
                 log::warn!(
                     "ConfigChanged webhook failed for workspace: {}",
                     workspace_context.settings.workspace_name
                 );
             }
 
             #[cfg(feature = "high-performance-mode")]
             put_config_in_redis(
                 version_id,
                 state,
                 &workspace_context.schema_name,
                 &mut conn,
             )
             .await?;
+
+            if !webhook_status {
+                return Ok(HttpResponse::build(
+                    actix_web::http::StatusCode::from_u16(512)
+                        .unwrap_or(actix_web::http::StatusCode::INTERNAL_SERVER_ERROR),
+                )
+                .finish());
+            }
         }
         resp
🤖 Prompt for AI Agents
In `@crates/context_aware_config/src/api/default_config/handlers.rs` around lines
565 - 585, The delete handler currently calls trigger_config_changed_webhook and
only logs when webhook_status is false, then continues to return 204; change it
to mirror create/update behavior by returning an error response when the webhook
call fails: after calling trigger_config_changed_webhook (the webhook_status
boolean), if webhook_status is false return the same 512-style error response
used by create/update handlers instead of just logging. Update the control flow
around trigger_config_changed_webhook in the delete path (references:
trigger_config_changed_webhook, webhook_status, the delete handler that
currently returns 204) so webhook failures propagate to the client consistently.

Comment on lines 249 to 283
pub async fn trigger_config_changed_webhook(
version_id: i64,
workspace_context: &WorkspaceContext,
state: &Data<AppState>,
db_conn: &mut DBConnection,
user: &User,
change_reason: &str,
) -> bool {
let payload = json!({
"change_reason": change_reason,
"config_version": version_id,
});

if let Ok(webhook) = fetch_webhook_by_event(
state,
user,
&WebhookEvent::ConfigChanged,
workspace_context,
)
.await
{
execute_webhook_call(
&webhook,
&payload,
&Some(version_id.to_string()),
workspace_context,
WebhookEvent::ConfigChanged,
state,
db_conn,
)
.await
} else {
true
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Webhook fetch errors are treated as success.
If fetch_webhook_by_event fails (network/5xx), this returns true, so callers respond 200 even though the webhook wasn’t sent. Consider logging and returning false so 512 semantics apply.

🛠️ Suggested fix
-    if let Ok(webhook) = fetch_webhook_by_event(
-        state,
-        user,
-        &WebhookEvent::ConfigChanged,
-        workspace_context,
-    )
-    .await
-    {
-        execute_webhook_call(
-            &webhook,
-            &payload,
-            &Some(version_id.to_string()),
-            workspace_context,
-            WebhookEvent::ConfigChanged,
-            state,
-            db_conn,
-        )
-        .await
-    } else {
-        true
-    }
+    match fetch_webhook_by_event(
+        state,
+        user,
+        &WebhookEvent::ConfigChanged,
+        workspace_context,
+    )
+    .await
+    {
+        Ok(webhook) => {
+            execute_webhook_call(
+                &webhook,
+                &payload,
+                &Some(version_id.to_string()),
+                workspace_context,
+                WebhookEvent::ConfigChanged,
+                state,
+                db_conn,
+            )
+            .await
+        }
+        Err(err) => {
+            log::error!("Failed to fetch ConfigChanged webhook: {err}");
+            false
+        }
+    }
🤖 Prompt for AI Agents
In `@crates/context_aware_config/src/helpers.rs` around lines 249 - 283, In
trigger_config_changed_webhook, treat a failed fetch_webhook_by_event as a
failure instead of success: when fetch_webhook_by_event returns Err, log the
error (use the project logger available in AppState or tracing::error) and
return false rather than true so callers receive the correct failure semantics;
keep the successful path that calls execute_webhook_call(...) for the Ok case
and ensure the log message references WebhookEvent::ConfigChanged and the
version_id to aid debugging.

@sauraww sauraww force-pushed the feat/config-change-webhook-event branch from 92f3b73 to 9197251 Compare February 13, 2026 05:36
@Datron Datron added the P0 label Feb 13, 2026
@sauraww sauraww force-pushed the feat/config-change-webhook-event branch 2 times, most recently from 7f60e14 to 381648f Compare February 16, 2026 06:30
}

#[derive(Deref, DerefMut, Clone, Debug)]
#[derive(Deref, DerefMut, Clone, Debug, Serialize, Deserialize)]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These types are usually added to inject a value into handlers. They don't really need these traits

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same for the other types in this file

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1
please revert changes to this file

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let version_id = add_config_version(
&state,
tags,
req_change_reason.into(),
transaction_conn,
&workspace_context.schema_name,
)?;
Ok((put_response, version_id))
})?;

Can you add the trigger for the webhook in add_config_version?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No , add_config_version is synchronous and the trigger is async , we cannot call async function inside transaction.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But you can return future which can be awaited on outside the synchronous block of the transaction

Anyways, on failure of webhook we dont even need to revert the queries so response awaiting outside transaction is safe as well

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a slight problem with this approach - I would be using execute_webhook_call which needs &mut DBConnection, but the transaction still holds the mutable borrow when we create the future. The future can't capture db_conn — the borrow checker won't allow it.
You can't return a future that captures &mut DBConnection from inside a transaction because the connection's lifetime is scoped to the transaction closure.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Explanation:
Modified add_config_version:

pub fn add_config_version<'a, T>(
    state: &'a Data<AppState>,
    tags: Option<Vec<String>>,
    description: Description,
    db_conn: &'a mut DBConnection,
    workspace_context: &'a WorkspaceContext,
    payload: &'a T,
) -> superposition::Result<(i64, Pin<Box<dyn Future<Output = bool> + Send + 'a>>)>
where
    T: Serialize + Send + Sync,
{
    use config_versions::dsl::config_versions;
    let version_id = generate_snowflake_id(state)?;
    let config = generate_cac(db_conn, &workspace_context.schema_name)?;
    let json_config = json!(config);
    let config_hash = blake3::hash(json_config.to_string().as_bytes()).to_string();

    let config_version = ConfigVersion {
        id: version_id,
        config: json_config,
        config_hash,
        tags,
        created_at: Utc::now(),
        description,
    };
    diesel::insert_into(config_versions)
        .values(&config_version)
        .returning(ConfigVersion::as_returning())
        .schema_name(&workspace_context.schema_name)
        .execute(db_conn)?;

    let webhook_future = Box::pin(async move {
        execute_webhook_call(
            payload,
            &Some(version_id.to_string()),
            workspace_context,
            WebhookEvent::ConfigChanged,
            state,
            db_conn,
        )
        .await
    });

    Ok((version_id, webhook_future))
}

Sample Usage:

#[authorized]
#[put("")]
async fn create_handler(
    workspace_context: WorkspaceContext,
    state: Data<AppState>,
    custom_headers: CustomHeaders,
    req: Json<PutRequest>,
    mut db_conn: DbConnection,
    user: User,
) -> superposition::Result<HttpResponse> {
    let tags = parse_config_tags(custom_headers.config_tags)?;
    let description = match req.description.clone() {
        Some(val) => val,
        None => {
            // TODO: get rid of `query_description` function altogether
            let resp = query_description(
                Value::Object(req.context.clone().into_inner().into()),
                &mut db_conn,
                &workspace_context.schema_name,
            );
            match resp {
                Err(AppError::DbError(diesel::result::Error::NotFound)) => {
                    return Err(bad_argument!(
                        "Description is required when context does not exist"
                    ));
                }
                Ok(desc) => desc,
                Err(e) => return Err(e),
            }
        }
    };
    let req_change_reason = req.change_reason.clone();

    validate_change_reason(
        &workspace_context,
        &req_change_reason,
        &mut db_conn,
        &state.master_encryption_key,
    )?;

    let (put_response, version_id, webhook_future) = db_conn
        .transaction::<_, superposition::AppError, _>(|transaction_conn| {
            let put_response = operations::upsert(
                req.into_inner(),
                description,
                transaction_conn,
                true,
                &user,
                &workspace_context,
                false,
                &state.master_encryption_key,
            )
            .map_err(|err: superposition::AppError| {
                log::error!("context put failed with error: {:?}", err);
                err
            })?;

            let (version_id, future_webhook) = add_config_version(
                &state,
                tags,
                req_change_reason.into(),
                transaction_conn,
                &workspace_context,
                &put_response,
            )?;
            Ok((put_response, version_id, future_webhook))
        })?;

    let webhook_status = webhook_future.await;

    let mut http_resp = if webhook_status {
        HttpResponse::Ok()
    } else {
        HttpResponse::build(
            actix_web::http::StatusCode::from_u16(512)
                .unwrap_or(actix_web::http::StatusCode::INTERNAL_SERVER_ERROR),
        )
    };

    http_resp.insert_header((
        AppHeader::XConfigVersion.to_string(),
        version_id.to_string(),
    ));

    #[cfg(feature = "high-performance-mode")]
    put_config_in_redis(version_id, state, &workspace_context.schema_name, &mut conn)
        .await?;

    Ok(http_resp.json(put_response))
}

You will get an error saying :

lifetime may not live long enough
returning this value requires that `'1` must outlive `'2`

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is that the future borrows transaction_conn, which only lives for the duration of the transaction closure — but we're trying to return the future out of the closure and .await it after the transaction completes.
We can't borrow transaction_conn in a future that outlives the transaction.

db_conn: &mut DBConnection,
user: &User,
change_reason: &str,
) -> bool {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Return result here, so you can throw 512 when it does error out

Comment on lines 257 to 260
let payload = json!({
"change_reason": change_reason,
"config_version": version_id,
});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be better to also include the new config json? The entire CAC config?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why would that be needed ?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For an experiment webhook we send the experiment data, for this webhook it makes sense to send the current config data

Comment on lines 593 to 639
pub async fn fetch_webhook_by_event(
state: &Data<AppState>,
user: &User,
event: &WebhookEvent,
workspace_context: &WorkspaceContext,
) -> result::Result<Webhook> {
let http_client = reqwest::Client::new();
let url = format!("{}/webhook/event/{event}", state.cac_host);
let user_str = serde_json::to_string(user).map_err(|err| {
log::error!("Something went wrong, failed to stringify user data {err}");
unexpected_error!(
"Something went wrong, failed to stringify user data {}",
err
)
})?;

let headers_map =
construct_header_map(workspace_context, vec![("x-user", user_str)])?;

let response = http_client
.get(&url)
.headers(headers_map)
.header(
header::AUTHORIZATION,
format!("Internal {}", state.superposition_token),
)
.send()
.await;

match response {
Ok(res) => {
if res.status() == 404 {
log::info!("No Webhook found for event: {}", event);
return Ok(Webhook::default());
}
let webhook = res.json::<Webhook>().await.map_err(|err| {
log::error!("failed to parse Webhook response with error: {}", err);
unexpected_error!("Failed to parse Webhook.")
})?;
Ok(webhook)
}
Err(error) => {
log::error!("Failed to fetch Webhook with error: {:?}", error);
Err(unexpected_error!(error))
}
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you have moved the code here to service utils, make a straight away DB call, why bother having all this indirect calls, when its moved to service_utils

it just simplifies everything

}
}

pub fn construct_header_map(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
pub fn construct_header_map(
pub fn construct_cac_headers_map(

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not needed since this would in cac_api.rs

}
}

pub fn construct_header_map(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also, I think after changing fetch_webhook_by_event to a DB call instead of API call, this function will not be needed outside the scope of experimentation_platform crate
we can move it back then

Ok(version_id)
}

pub async fn trigger_config_changed_webhook(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we move both the trigger function to service_utils have them unified ?
will that possible ?

if not what is the blocker for this ?

@sauraww sauraww force-pushed the feat/config-change-webhook-event branch from 381648f to b76e2de Compare February 17, 2026 11:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants