-
Notifications
You must be signed in to change notification settings - Fork 231
Description
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
- Create shared component at
.github/workflows/shared/round-robin-processor.md - Implement core state management utilities
- Add utility functions: select-next, update-state, reset-cycle
- Test with
gpclean.mdas proof-of-concept - Document advanced patterns (priority, weighted selection)
- Migrate
daily-workflow-updater.md - Migrate remaining workflows
- 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
- Correctness: Centralized testing ensures the logic is bug-free
- Features: Easy to add advanced features (priority, weights, time-based resets)
- Observability: Shared component can emit metrics on cycle progress
- Documentation: Pattern is self-documenting through shared component
- Error Handling: Centralized error handling for edge cases
AI generated by Workflow Skill Extractor
- expires on Feb 14, 2026, 12:05 AM UTC