Skip to content

feat: update refill workflow for identity-based credits#4194

Closed
Flo4604 wants to merge 6 commits intofeat/identity-credits-go-servicesfrom
feat/identity-credits-workflow
Closed

feat: update refill workflow for identity-based credits#4194
Flo4604 wants to merge 6 commits intofeat/identity-credits-go-servicesfrom
feat/identity-credits-workflow

Conversation

@Flo4604
Copy link
Member

@Flo4604 Flo4604 commented Oct 28, 2025

What does this PR do?

Updates the workflow we use for refilling the credits to use the new credits table if key uses it otherwise does the old refill.

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • Chore (refactoring code, technical debt, workflow improvements)
  • Enhancement (small improvements)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How should this be tested?

Make sure credits get refilled for both keys and identities.

cd apps/workflows
npx wrangler dev --test-scheduled
curl "http://localhost:8787/__scheduled?cron=0+0+*+*+*"

This should trigger the refill.

Checklist

Required

  • Filled out the "How to test" section in this PR
  • Read Contributing Guide
  • Self-reviewed my own code
  • Commented on my code in hard-to-understand areas
  • Ran pnpm build
  • Ran pnpm fmt
  • Checked for warnings, there are none
  • Removed all console.logs
  • Merged the latest changes from main onto my branch with git pull origin main
  • My changes don't cause any responsiveness issues

Appreciated

  • If a UI change was made: Added a screen recording or screenshots to this PR
  • Updated the Unkey Docs if changes were necessary

@changeset-bot
Copy link

changeset-bot bot commented Oct 28, 2025

⚠️ No Changeset found

Latest commit: 768e60b

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@vercel
Copy link

vercel bot commented Oct 28, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
dashboard Ready Ready Preview Comment Nov 4, 2025 5:16pm
1 Skipped Deployment
Project Deployment Preview Comments Updated (UTC)
engineering Ignored Ignored Preview Nov 4, 2025 5:16pm

Copy link
Member Author

Flo4604 commented Oct 28, 2025

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 28, 2025

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

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.

📝 Walkthrough

Walkthrough

The refill_keys workflow is refactored to support dual data paths: modern credits table entries and legacy key entries. Each path applies date-based refill logic with existence checks, updates respective database records in a transaction, and generates corresponding audit logs with resource-specific event types. The return structure changes to report refilled credits and legacy keys separately.

Changes

Cohort / File(s) Summary
Refill workflow dual-path refactoring
apps/workflows/src/workflows/refill_keys.ts
Splits refill logic into two data paths: credits with joined key/identity checks (isLegacy: false) and legacy keys without credits entries (isLegacy: true). Updates transaction logic to handle both paths differently. Reworks audit logging with dynamic targets and resource-type-dependent event types. Returns refillCreditIds and refillLegacyKeyIds instead of single refillKeyIds array.

Sequence Diagram(s)

sequenceDiagram
    participant Workflow
    participant Database
    participant Transaction
    participant AuditLog
    participant Return

    Workflow->>Database: Fetch credits with date/existence filters
    Workflow->>Database: Fetch legacy keys (no credits match)
    
    rect rgb(240, 248, 255)
        Note over Workflow,Transaction: Process both data paths
        Workflow->>Workflow: Merge credits and legacy items
        Workflow->>Workflow: Calculate refill amounts (date logic)
    end
    
    Workflow->>Transaction: Begin transaction
    Transaction->>Database: Update credits (remaining, refilledAt, updatedAt)
    Transaction->>Database: Update legacy keys (remaining)
    Transaction->>AuditLog: Log dynamic audit events<br/>(by resource type & target)
    AuditLog-->>Transaction: Confirm
    Transaction-->>Workflow: Commit
    
    Workflow->>Return: Return refillCreditIds & refillLegacyKeyIds
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~35 minutes

  • Data fetch logic: Verify correctness of date-based filtering, existence checks, and query joins for both credits and legacy paths
  • Transaction handling: Ensure proper field updates for each data path (legacy vs. non-legacy) and transaction atomicity
  • Audit logging: Validate dynamic audit target construction and event-type selection based on resource types
  • Return structure change: Confirm all callers handle the new refillCreditIds and refillLegacyKeyIds fields

Pre-merge checks and finishing touches

✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title 'feat: update refill workflow for identity-based credits' directly aligns with the main change in the pull request. The raw summary confirms that the workflow has been updated to handle both identity-based credits (new credits table) and legacy keys, which is precisely what the title conveys. The title is concise, specific, and clearly communicates the primary change.
Description check ✅ Passed The pull request description follows the required template structure with all necessary sections completed: a clear summary of what the PR does, the type of change marked as 'New feature', detailed testing instructions with specific commands provided, and all required checklist items marked as complete. The description adequately explains the purpose and provides sufficient detail for reviewers to understand the changes.

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.

@vercel vercel bot temporarily deployed to Preview – engineering October 28, 2025 14:13 Inactive
@vercel vercel bot temporarily deployed to Preview – dashboard October 28, 2025 14:15 Inactive
@Flo4604 Flo4604 force-pushed the feat/identity-credits-go-services branch from 6668e81 to 8a07fb8 Compare October 28, 2025 15:13
@Flo4604 Flo4604 force-pushed the feat/identity-credits-workflow branch from 2d83e5c to d434978 Compare October 28, 2025 15:13
@vercel vercel bot temporarily deployed to Preview – engineering October 28, 2025 15:14 Inactive
@vercel vercel bot temporarily deployed to Preview – dashboard October 28, 2025 15:14 Inactive
@Flo4604 Flo4604 force-pushed the feat/identity-credits-workflow branch from d434978 to 6dbce05 Compare October 28, 2025 21:09
@Flo4604 Flo4604 force-pushed the feat/identity-credits-go-services branch from 8a07fb8 to 82018c9 Compare October 28, 2025 21:09
@vercel vercel bot temporarily deployed to Preview – engineering October 28, 2025 21:10 Inactive
@vercel vercel bot temporarily deployed to Preview – dashboard October 28, 2025 21:10 Inactive
@Flo4604 Flo4604 force-pushed the feat/identity-credits-go-services branch from 82018c9 to 723c836 Compare October 28, 2025 21:45
@Flo4604 Flo4604 force-pushed the feat/identity-credits-workflow branch from 6dbce05 to 68ae12d Compare October 28, 2025 21:45
@vercel vercel bot temporarily deployed to Preview – engineering October 28, 2025 21:46 Inactive
@vercel vercel bot temporarily deployed to Preview – dashboard October 28, 2025 21:46 Inactive
@Flo4604 Flo4604 force-pushed the feat/identity-credits-go-services branch from 723c836 to 6e6a1ec Compare October 28, 2025 22:40
@Flo4604 Flo4604 force-pushed the feat/identity-credits-workflow branch from 68ae12d to 8097e24 Compare October 28, 2025 22:40
@vercel vercel bot temporarily deployed to Preview – engineering October 28, 2025 22:41 Inactive
@vercel vercel bot temporarily deployed to Preview – dashboard October 28, 2025 22:41 Inactive
@Flo4604 Flo4604 force-pushed the feat/identity-credits-workflow branch from 8097e24 to a5ab7f7 Compare October 29, 2025 09:51
@vercel vercel bot temporarily deployed to Preview – engineering October 29, 2025 09:52 Inactive
@vercel vercel bot temporarily deployed to Preview – dashboard October 29, 2025 09:52 Inactive
@vercel vercel bot temporarily deployed to Preview – dashboard October 30, 2025 09:15 Inactive
@Flo4604 Flo4604 mentioned this pull request Oct 30, 2025
18 tasks
@Flo4604 Flo4604 force-pushed the feat/identity-credits-go-services branch from abb3650 to 6240d77 Compare October 30, 2025 13:48
@Flo4604 Flo4604 force-pushed the feat/identity-credits-workflow branch from 4f072a6 to 5d3d6f6 Compare October 30, 2025 13:48
@vercel vercel bot temporarily deployed to Preview – engineering October 30, 2025 13:49 Inactive
@vercel vercel bot temporarily deployed to Preview – dashboard October 30, 2025 13:49 Inactive
@Flo4604 Flo4604 force-pushed the feat/identity-credits-go-services branch from 6240d77 to ac969b1 Compare October 30, 2025 15:08
@Flo4604 Flo4604 force-pushed the feat/identity-credits-workflow branch from 5d3d6f6 to 922ec04 Compare October 30, 2025 15:08
@vercel vercel bot temporarily deployed to Preview – engineering October 30, 2025 15:08 Inactive
@vercel vercel bot temporarily deployed to Preview – dashboard October 30, 2025 15:09 Inactive
@Flo4604 Flo4604 force-pushed the feat/identity-credits-workflow branch from 922ec04 to 3856684 Compare October 30, 2025 15:12
@Flo4604 Flo4604 force-pushed the feat/identity-credits-go-services branch from ac969b1 to 2819cf3 Compare October 30, 2025 15:12
@vercel vercel bot temporarily deployed to Preview – engineering October 30, 2025 15:13 Inactive
@vercel vercel bot temporarily deployed to Preview – dashboard October 30, 2025 15:13 Inactive
@Flo4604 Flo4604 marked this pull request as ready for review October 30, 2025 16:36
@Flo4604
Copy link
Member Author

Flo4604 commented Oct 30, 2025

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 30, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@github-actions
Copy link
Contributor

github-actions bot commented Oct 30, 2025

Thank you for following the naming conventions for pull request titles! 🙏

@Flo4604
Copy link
Member Author

Flo4604 commented Nov 3, 2025

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 3, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/workflows/src/workflows/refill_keys.ts (1)

20-22: Fix timezone inconsistency in date calculations.

lastDayOfMonth is calculated using local timezone methods (getMonth(), getFullYear(), getDate()), while today uses UTC (getUTCDate()). This inconsistency could cause incorrect refill behavior when comparing these values, especially at timezone boundaries.

Apply this diff to make both calculations use UTC:

-    const lastDayOfMonth = new Date(now.getFullYear(), now.getMonth() + 1, 0).getDate();
+    const lastDayOfMonth = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() + 1, 0)).getUTCDate();
     const today = now.getUTCDate();
🧹 Nitpick comments (1)
apps/workflows/src/workflows/refill_keys.ts (1)

150-151: Consider adding a defensive check for resource identification.

While the queries ensure either keyId or identityId exists, adding a defensive check or comment would improve code robustness and clarity.

Consider adding a check:

     for (const credit of allToRefill) {
+      if (!credit.keyId && !credit.identityId) {
+        console.error(`Credit ${credit.id} has neither keyId nor identityId, skipping`);
+        continue;
+      }
       const resourceType = credit.keyId ? "key" : "identity";

Or at minimum, add a comment explaining the assumption:

+    // Each credit has either keyId or identityId (ensured by queries)
     const resourceType = credit.keyId ? "key" : "identity";
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1da861e and 00b50c8.

📒 Files selected for processing (1)
  • apps/workflows/src/workflows/refill_keys.ts (2 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: Flo4604
Repo: unkeyed/unkey PR: 4190
File: go/internal/services/keys/verifier.go:51-53
Timestamp: 2025-10-30T15:10:52.710Z
Learning: PR #4190 for unkeyed/unkey is focused solely on database schema and query changes for identity-based credits. It adds IdentityCredits and KeyCredits fields to structs and queries, but does not implement the priority enforcement logic in the usagelimiter. The logic implementation is intentionally deferred to a later PR in the stack.
Learnt from: imeyer
Repo: unkeyed/unkey PR: 3755
File: .github/workflows/runbook-freshness-check.yaml:157-173
Timestamp: 2025-08-08T14:59:52.283Z
Learning: Repo unkeyed/unkey: When a CI/workflow fix is deferred, imeyer prefers a thorough GitHub issue be opened with sections (Summary, Impact, Where, Repro, Observed vs Expected, Acceptance Criteria, Validation Plan, Out of Scope, References) and assigned to imeyer, including backlinks to the originating PR and comment.
📚 Learning: 2025-10-30T15:10:52.710Z
Learnt from: Flo4604
Repo: unkeyed/unkey PR: 4190
File: go/internal/services/keys/verifier.go:51-53
Timestamp: 2025-10-30T15:10:52.710Z
Learning: PR #4190 for unkeyed/unkey is focused solely on database schema and query changes for identity-based credits. It adds IdentityCredits and KeyCredits fields to structs and queries, but does not implement the priority enforcement logic in the usagelimiter. The logic implementation is intentionally deferred to a later PR in the stack.

Applied to files:

  • apps/workflows/src/workflows/refill_keys.ts
🔇 Additional comments (6)
apps/workflows/src/workflows/refill_keys.ts (6)

31-97: Well-structured credits query with comprehensive filtering.

The query correctly uses left joins to validate related entities at the database level and filters out deleted keys/identities. The date-based refill logic properly handles end-of-month edge cases.


100-145: Excellent double-refill prevention for legacy keys.

The query correctly filters out keys that already have a credits entry (line 133) to prevent double refills. The mapping structure maintains consistency with the credits query results.


154-173: Correct handling of legacy and modern credit updates.

The conditional logic appropriately updates the respective tables with the correct IDs and field types. The differences in field names (lastRefillAt vs refilledAt) and date formats (Date object vs timestamp) are appropriate for the respective schemas.


176-223: Well-designed dynamic audit logging.

The audit log construction correctly handles different resource types with appropriate targets and event types. The defensive approach of conditionally adding both key and identity targets provides flexibility.


149-227: Verify error handling strategy for individual refills.

The current implementation will stop the entire workflow if any single refill fails. Consider whether partial completion (refilling successful items even if some fail) would be more appropriate for a scheduled background job.

If partial completion is desired, consider adding error handling:

for (const credit of allToRefill) {
  const resourceType = credit.keyId ? "key" : "identity";
  const resourceId = credit.keyId || credit.identityId;
  await step.do(`refilling ${credit.id} (${resourceType})`, async () => {
    try {
      await db.transaction(async (tx) => {
        // ... existing transaction logic
      });
      return { creditId: credit.id, resourceType, resourceId };
    } catch (error) {
      console.error(`Failed to refill ${credit.id}:`, error);
      return { creditId: credit.id, error: error.message, skipped: true };
    }
  });
}

Otherwise, if fail-fast is intentional, consider adding a comment explaining this behavior.


234-236: Clear and informative return structure.

Separating refilled credits and legacy keys in the return value provides good visibility into the workflow execution and helps distinguish between the two data paths.

Flo4604 and others added 6 commits November 4, 2025 18:10
- Update refill_keys workflow to use new credits table
- Refactor to work with credit-based refill configuration
- Simplify workflow logic by leveraging credits table structure
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant