Skip to content

[refactoring] Extract "Cache-Memory Round-Robin Processing" into shared component #15038

@github-actions

Description

@github-actions

Skill Overview

Many workflows use cache-memory to implement round-robin or sequential processing patterns. This ensures systematic coverage of items (dependencies, workflows, etc.) without duplicate work or skipping items.

Why this should be shared: The round-robin state tracking logic is complex and error-prone. Multiple workflows implement similar logic with slight variations, leading to bugs and maintenance burden. A shared component with standardized patterns would make this common workflow pattern much easier to implement correctly.

Current Usage

This skill appears in the following workflows:

  • gpclean.md (lines 56-95) - Round-robin module selection from go.mod dependencies
  • daily-workflow-updater.md - Sequential workflow processing
  • hourly-ci-cleaner.md - Rotating through workflow runs
  • stale-repo-identifier.md - Sequential repository scanning
  • workflow-health-manager.md - Systematic workflow health checks
  • Additional 3-5 workflows use similar patterns

Total: ~8-10 workflows use round-robin/sequential processing

Proposed Shared Component

File: .github/workflows/shared/round-robin-processor.md

Configuration:

---
tools:
  cache-memory: true
  bash:
    - "jq *"
    - "date *"
    - "mkdir *"

steps:
  - name: Setup round-robin state
    id: round-robin-setup
    run: |
      set -e
      
      # Create cache directory
      mkdir -p /tmp/gh-aw/cache-memory/round-robin
      
      # Default state file location
      STATE_FILE="/tmp/gh-aw/cache-memory/round-robin/state.json"
      
      # Initialize state if doesn't exist
      if [ ! -f "$STATE_FILE" ]; then
        echo '{
          "last_checked_item": "",
          "last_check_date": "",
          "checked_items": [],
          "total_items": 0,
          "current_index": 0,
          "cycle_count": 0
        }' > "$STATE_FILE"
        echo "Initialized new round-robin state"
      fi
      
      echo "state_file=$STATE_FILE" >> "$GITHUB_OUTPUT"
      echo "Round-robin state loaded"
---

# Round-Robin Processor

This shared component provides utilities for implementing round-robin or sequential item processing with state persistence across workflow runs.

## Use Cases

- **Dependency Scanning**: Systematically check each dependency without duplicates
- **Workflow Auditing**: Process workflows one at a time, cycling through all
- **Repository Scanning**: Check repositories in rotation
- **Issue Processing**: Handle issues sequentially without overwhelming

## State Management

State is stored in `/tmp/gh-aw/cache-memory/round-robin/state.json`:

``````json
{
  "last_checked_item": "item-id",
  "last_check_date": "2024-02-11",
  "checked_items": ["item1", "item2", "item3"],
  "total_items": 10,
  "current_index": 3,
  "cycle_count": 1
}

Utility Functions

Select Next Item

# Load state
STATE_FILE="/tmp/gh-aw/cache-memory/round-robin/state.json"
CHECKED_ITEMS=$(jq -r '.checked_items[]' "$STATE_FILE")

# Get all items to process
ALL_ITEMS=("item1" "item2" "item3" "item4")

# Find first unchecked item
SELECTED_ITEM=""
for item in "\$\{ALL_ITEMS[@]}"; do
  if ! echo "$CHECKED_ITEMS" | grep -q "^$item$"; then
    SELECTED_ITEM="$item"
    break
  fi
done

# If all checked, reset and start over
if [ -z "$SELECTED_ITEM" ]; then
  echo "All items checked, resetting cycle"
  SELECTED_ITEM="\$\{ALL_ITEMS[0]}"
  jq '.checked_items = [] | .cycle_count += 1' "$STATE_FILE" > "$STATE_FILE.tmp"
  mv "$STATE_FILE.tmp" "$STATE_FILE"
fi

echo "Selected item: $SELECTED_ITEM"

Update State After Processing

# Mark item as checked
STATE_FILE="/tmp/gh-aw/cache-memory/round-robin/state.json"
SELECTED_ITEM="item2"

jq --arg item "$SELECTED_ITEM" --arg date "$(date '+%Y-%m-%d')" '
  .last_checked_item = $item |
  .last_check_date = $date |
  .checked_items += [$item] |
  .checked_items |= unique |
  .current_index += 1
' "$STATE_FILE" > "$STATE_FILE.tmp"
mv "$STATE_FILE.tmp" "$STATE_FILE"

echo "State updated: $SELECTED_ITEM marked as checked"

Reset Cycle

# Reset for new cycle (all items will be checked again)
STATE_FILE="/tmp/gh-aw/cache-memory/round-robin/state.json"

jq '.checked_items = [] | .current_index = 0 | .cycle_count += 1' "$STATE_FILE" > "$STATE_FILE.tmp"
mv "$STATE_FILE.tmp" "$STATE_FILE"

echo "Cycle reset"

Example Usage Pattern

imports:
  - shared/round-robin-processor.md

# Your workflow
---

# 1. Get all items to process
ALL_ITEMS=$(cat items.txt)

# 2. Load state and select next item
STATE_FILE="/tmp/gh-aw/cache-memory/round-robin/state.json"
CHECKED_ITEMS=$(jq -r '.checked_items[]' "$STATE_FILE")

# 3. Select first unchecked item
# ... selection logic ...

# 4. Process the selected item
echo "Processing: $SELECTED_ITEM"
# ... do work ...

# 5. Update state
jq --arg item "$SELECTED_ITEM" '.checked_items += [$item] | .checked_items |= unique' "$STATE_FILE" > tmp.json
mv tmp.json "$STATE_FILE"

**Usage Example**:

``````yaml
# In gpclean.md (simplified from 40 lines to ~10 lines)

imports:
  - shared/round-robin-processor.md

# Load direct dependencies
DEPS=$(go list -m -json all | jq -r 'select(.Main != true) | .Path')

# Select next dependency to check (using shared utilities)
# ... use shared selection logic ...

# Process selected dependency
# ... GPL checking logic ...

# Update state (using shared utilities)
# ... use shared update logic ...

Impact

  • Workflows affected: 8-10 workflows
  • Lines saved: ~80-100 lines per workflow = 640-1,000 total lines
  • Maintenance benefit:
    • Single implementation of tricky state management logic
    • Reduces bugs from inconsistent implementations
    • Easier to add features (e.g., priority queues, item weights)
    • Self-documenting pattern for new workflow developers
    • Centralized testing and validation

Implementation Plan

  1. Create shared component at .github/workflows/shared/round-robin-processor.md
  2. Implement core state management utilities
  3. Add utility functions: select-next, update-state, reset-cycle
  4. Test with gpclean.md as proof-of-concept
  5. Document advanced patterns (priority, weighted selection)
  6. Migrate daily-workflow-updater.md
  7. Migrate remaining workflows
  8. Add monitoring/reporting for cycle completion

Example Before/After

Before (gpclean.md, lines 56-95):

steps:
  # 40 lines of state loading logic
  - name: Load tracking state
    run: |
      mkdir -p /tmp/gh-aw/cache-memory/gpclean/
      STATE_FILE="/tmp/gh-aw/cache-memory/gpclean/state.json"
      
      if [ ! -f "$STATE_FILE" ]; then
        echo '{"last_checked_module": "", "checked_modules": []}' > "$STATE_FILE"
      fi
      
  # 35 lines of selection logic
  - name: Select next module
    run: |
      CHECKED_MODULES=$(jq -r '.checked_modules[]' "$STATE_FILE")
      ALL_MODULES=$(go list -m all | awk '{print $1}')
      
      for module in $ALL_MODULES; do
        if ! echo "$CHECKED_MODULES" | grep -q "^$module$"; then
          SELECTED_MODULE="$module"
          break
        fi
      done
      
      if [ -z "$SELECTED_MODULE" ]; then
        # Reset and start over
        jq '.checked_modules = []' "$STATE_FILE" > tmp.json
        mv tmp.json "$STATE_FILE"
        SELECTED_MODULE=$(echo "$ALL_MODULES" | head -1)
      fi
      
  # 25 lines of state update logic
  - name: Update state
    run: |
      jq --arg mod "$SELECTED_MODULE" \
        '.last_checked_module = $mod | .checked_modules += [$mod] | .checked_modules |= unique' \
        "$STATE_FILE" > tmp.json
      mv tmp.json "$STATE_FILE"

After:

imports:
  - shared/round-robin-processor.md

# Use shared utilities (100 lines reduced to ~10-15)
ALL_MODULES=$(go list -m all)
SELECTED_MODULE=$(select-next-item "$ALL_MODULES")

# ... GPL checking logic ...

update-round-robin-state "$SELECTED_MODULE"

Related Analysis

This recommendation comes from the Workflow Skill Extractor analysis run on 2026-02-11. This pattern is particularly valuable because it's complex to implement correctly and reduces bugs significantly.

Additional Benefits

  1. Correctness: Centralized testing ensures the logic is bug-free
  2. Features: Easy to add advanced features (priority, weights, time-based resets)
  3. Observability: Shared component can emit metrics on cycle progress
  4. Documentation: Pattern is self-documenting through shared component
  5. Error Handling: Centralized error handling for edge cases

AI generated by Workflow Skill Extractor

  • expires on Feb 14, 2026, 12:05 AM UTC

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions