effect-patterns-scheduling
Effect-TS patterns for Scheduling. Use when working with scheduling in Effect-TS applications.
Install
mkdir -p .claude/skills/effect-patterns-scheduling && curl -L -o skill.zip "https://mcp.directory/api/skills/download/3566" && unzip -o skill.zip -d .claude/skills/effect-patterns-scheduling && rm skill.zipInstalls to .claude/skills/effect-patterns-scheduling
About this skill
Effect-TS Patterns: Scheduling
This skill provides 3 curated Effect-TS patterns for scheduling. Use this skill when working on tasks related to:
- scheduling
- Best practices in Effect-TS applications
- Real-world patterns and solutions
🟢 Beginner Patterns
Retry Failed Operations
Rule: Use Effect.retry with a Schedule to handle transient failures gracefully.
Good Example:
import { Effect, Schedule, Data } from "effect"
// ============================================
// 1. Define error types
// ============================================
class NetworkError extends Data.TaggedError("NetworkError")<{
readonly message: string
}> {}
class RateLimitError extends Data.TaggedError("RateLimitError")<{
readonly retryAfter: number
}> {}
class NotFoundError extends Data.TaggedError("NotFoundError")<{
readonly resource: string
}> {}
// ============================================
// 2. Simulate a flaky API call
// ============================================
let callCount = 0
const fetchData = Effect.gen(function* () {
callCount++
yield* Effect.log(`API call attempt ${callCount}`)
// Simulate intermittent failures
if (callCount < 3) {
return yield* Effect.fail(new NetworkError({ message: "Connection timeout" }))
}
return { data: "Success!", attempts: callCount }
})
// ============================================
// 3. Basic retry - fixed attempts
// ============================================
const withBasicRetry = fetchData.pipe(
Effect.retry(Schedule.recurs(5)) // Retry up to 5 times
)
// ============================================
// 4. Retry with delay
// ============================================
const withDelayedRetry = fetchData.pipe(
Effect.retry(
Schedule.spaced("500 millis").pipe(
Schedule.intersect(Schedule.recurs(5))
)
)
)
// ============================================
// 5. Retry only specific errors
// ============================================
const fetchWithErrors = (shouldFail: boolean) =>
Effect.gen(function* () {
if (shouldFail) {
// Randomly fail with different errors
const random = Math.random()
if (random < 0.5) {
return yield* Effect.fail(new NetworkError({ message: "Timeout" }))
} else if (random < 0.8) {
return yield* Effect.fail(new RateLimitError({ retryAfter: 1000 }))
} else {
return yield* Effect.fail(new NotFoundError({ resource: "user:123" }))
}
}
return "Data fetched!"
})
// Only retry network and rate limit errors, not NotFoundError
const retryTransientOnly = fetchWithErrors(true).pipe(
Effect.retry({
schedule: Schedule.recurs(3),
while: (error) =>
error._tag === "NetworkError" || error._tag === "RateLimitError",
})
)
// ============================================
// 6. Retry with exponential backoff
// ============================================
const withExponentialBackoff = fetchData.pipe(
Effect.retry(
Schedule.exponential("100 millis", 2).pipe( // 100ms, 200ms, 400ms...
Schedule.intersect(Schedule.recurs(5)) // Max 5 retries
)
)
)
// ============================================
// 7. Run and observe
// ============================================
const program = Effect.gen(function* () {
yield* Effect.log("Starting retry demo...")
// Reset counter
callCount = 0
const result = yield* withBasicRetry
yield* Effect.log(`Final result: ${JSON.stringify(result)}`)
})
Effect.runPromise(program)
Rationale:
Use Effect.retry to automatically retry operations that fail due to transient errors like network timeouts.
Many failures are temporary:
- Network issues - Connection drops, timeouts
- Rate limits - Too many requests
- Resource contention - Database locks
- Service restarts - Brief unavailability
Automatic retries handle these without manual intervention.
Your First Schedule
Rule: Use Schedule to control when and how often effects run.
Good Example:
import { Effect, Schedule } from "effect"
// ============================================
// 1. Retry a failing operation
// ============================================
let attempts = 0
const flakyOperation = Effect.gen(function* () {
attempts++
if (attempts < 3) {
yield* Effect.log(`Attempt ${attempts} failed`)
return yield* Effect.fail(new Error("Temporary failure"))
}
return `Success on attempt ${attempts}`
})
// Retry up to 5 times
const withRetry = flakyOperation.pipe(
Effect.retry(Schedule.recurs(5))
)
// ============================================
// 2. Repeat a successful operation
// ============================================
const logTime = Effect.gen(function* () {
const now = new Date().toISOString()
yield* Effect.log(`Current time: ${now}`)
return now
})
// Repeat 3 times
const repeated = logTime.pipe(
Effect.repeat(Schedule.recurs(3))
)
// ============================================
// 3. Add delays between operations
// ============================================
// Repeat every second, 5 times
const polling = logTime.pipe(
Effect.repeat(
Schedule.spaced("1 second").pipe(
Schedule.intersect(Schedule.recurs(5))
)
)
)
// ============================================
// 4. Common schedule patterns
// ============================================
// Fixed delay between attempts
const fixedDelay = Schedule.spaced("500 millis")
// Increasing delay (1s, 2s, 4s, 8s...)
const exponentialBackoff = Schedule.exponential("1 second")
// Maximum number of attempts
const limitedAttempts = Schedule.recurs(3)
// Combine: exponential backoff, max 5 attempts
const retryPolicy = Schedule.exponential("100 millis").pipe(
Schedule.intersect(Schedule.recurs(5))
)
// ============================================
// 5. Run examples
// ============================================
const program = Effect.gen(function* () {
yield* Effect.log("--- Retry Example ---")
const result = yield* withRetry
yield* Effect.log(`Result: ${result}`)
yield* Effect.log("\n--- Repeat Example ---")
yield* repeated
})
Effect.runPromise(program)
Rationale:
Use Schedule to control timing in Effect programs - retrying failed operations, repeating successful ones, or adding delays.
Schedules solve common timing problems:
- Retries - Try again after failures
- Polling - Check for updates periodically
- Rate limiting - Control how fast things run
- Backoff - Increase delays between attempts
🟡 Intermediate Patterns
Scheduling Pattern 1: Repeat an Effect on a Fixed Interval
Rule: Repeat effects at fixed intervals using Schedule.fixed for steady-state operations and background tasks.
Good Example:
This example demonstrates a health check service that polls multiple service endpoints every 30 seconds and reports their status.
import { Effect, Schedule, Duration } from "effect";
interface ServiceStatus {
readonly service: string;
readonly url: string;
readonly isHealthy: boolean;
readonly responseTime: number;
readonly lastChecked: number;
}
// Mock health check that calls an endpoint
const checkServiceHealth = (
url: string,
service: string
): Effect.Effect<ServiceStatus> =>
Effect.gen(function* () {
const startTime = Date.now();
// Simulate HTTP call with occasional failures
const isHealthy = Math.random() > 0.1; // 90% success rate
const responseTime = Math.random() * 500; // 0-500ms
yield* Effect.sleep(Duration.millis(Math.round(responseTime)));
if (!isHealthy) {
yield* Effect.fail(new Error(`${service} is unhealthy`));
}
return {
service,
url,
isHealthy: true,
responseTime: Math.round(Date.now() - startTime),
lastChecked: Date.now(),
};
});
// Health check for multiple services
interface HealthCheckConfig {
readonly services: Array<{
readonly name: string;
readonly url: string;
}>;
readonly intervalSeconds: number;
}
// Keep track of service status
const serviceStatuses = new Map<string, ServiceStatus>();
// Check all services and report status
const checkAllServices = (
config: HealthCheckConfig
): Effect.Effect<void> =>
Effect.gen(function* () {
for (const service of config.services) {
const status = yield* checkServiceHealth(service.url, service.name).pipe(
Effect.either
);
if (status._tag === "Right") {
serviceStatuses.set(service.name, status.right);
console.log(
`✓ ${service.name}: OK (${status.right.responseTime}ms)`
);
} else {
console.log(`✗ ${service.name}: FAILED`);
// Keep last known status if available
}
}
});
// Create the repeating health check
const createHealthCheckScheduler = (
config: HealthCheckConfig
): Effect.Effect<void> =>
checkAllServices(config).pipe(
// Schedule with fixed interval (fixed = ignore execution time)
Effect.repeat(
Schedule.fixed(Duration.seconds(config.intervalSeconds))
)
);
// Report current status
const reportStatus = (): Effect.Effect<void> =>
Effect.sync(() => {
if (serviceStatuses.size === 0) {
console.log("\n[STATUS] No services checked yet");
return;
}
console.log("\n[STATUS REPORT]");
for (const [service, status] of serviceStatuses) {
const ago = Math.round((Date.now() - status.lastChecked) / 1000);
console.log(
` ${service}: ${status.isHealthy ? "✓" : "✗"} (checked ${ago}s ago)`
);
}
});
// Run health checker in background and check status periodically
const program = Effect.gen(function* () {
const config: HealthCheckConfig = {
services: [
{ name: "API", url: "https://api.example.com/health" },
{ name: "Database", url: "https://db.example.com/health" },
{ name: "Cache", url: "https://cache.example.com/health" },
],
inter
---
*Content truncated.*
More by PaulJPhilp
View all skills by PaulJPhilp →You might also like
flutter-development
aj-geddes
Build beautiful cross-platform mobile apps with Flutter and Dart. Covers widgets, state management with Provider/BLoC, navigation, API integration, and material design.
drawio-diagrams-enhanced
jgtolentino
Create professional draw.io (diagrams.net) diagrams in XML format (.drawio files) with integrated PMP/PMBOK methodologies, extensive visual asset libraries, and industry-standard professional templates. Use this skill when users ask to create flowcharts, swimlane diagrams, cross-functional flowcharts, org charts, network diagrams, UML diagrams, BPMN, project management diagrams (WBS, Gantt, PERT, RACI), risk matrices, stakeholder maps, or any other visual diagram in draw.io format. This skill includes access to custom shape libraries for icons, clipart, and professional symbols.
ui-ux-pro-max
nextlevelbuilder
"UI/UX design intelligence. 50 styles, 21 palettes, 50 font pairings, 20 charts, 8 stacks (React, Next.js, Vue, Svelte, SwiftUI, React Native, Flutter, Tailwind). Actions: plan, build, create, design, implement, review, fix, improve, optimize, enhance, refactor, check UI/UX code. Projects: website, landing page, dashboard, admin panel, e-commerce, SaaS, portfolio, blog, mobile app, .html, .tsx, .vue, .svelte. Elements: button, modal, navbar, sidebar, card, table, form, chart. Styles: glassmorphism, claymorphism, minimalism, brutalism, neumorphism, bento grid, dark mode, responsive, skeuomorphism, flat design. Topics: color palette, accessibility, animation, layout, typography, font pairing, spacing, hover, shadow, gradient."
godot
bfollington
This skill should be used when working on Godot Engine projects. It provides specialized knowledge of Godot's file formats (.gd, .tscn, .tres), architecture patterns (component-based, signal-driven, resource-based), common pitfalls, validation tools, code templates, and CLI workflows. The `godot` command is available for running the game, validating scripts, importing resources, and exporting builds. Use this skill for tasks involving Godot game development, debugging scene/resource files, implementing game systems, or creating new Godot components.
nano-banana-pro
garg-aayush
Generate and edit images using Google's Nano Banana Pro (Gemini 3 Pro Image) API. Use when the user asks to generate, create, edit, modify, change, alter, or update images. Also use when user references an existing image file and asks to modify it in any way (e.g., "modify this image", "change the background", "replace X with Y"). Supports both text-to-image generation and image-to-image editing with configurable resolution (1K default, 2K, or 4K for high resolution). DO NOT read the image file first - use this skill directly with the --input-image parameter.
fastapi-templates
wshobson
Create production-ready FastAPI projects with async patterns, dependency injection, and comprehensive error handling. Use when building new FastAPI applications or setting up backend API projects.
Related MCP Servers
Browse all serversIntegrate real-time workday and hour calculations with Timor API. Simplify scheduling using our workday calculator for a
MCP server connects Claude and AI coding tools to shadcn/ui components. Accurate TypeScript props and React component da
Boost your AI code assistant with Context7: inject real-time API documentation from OpenAPI specification sources into y
By Sentry. MCP server and CLI that provides tools for AI agents working on iOS and macOS Xcode projects. Build, test, li
Securely join MySQL databases with Read MySQL for read-only query access and in-depth data analysis.
Context Portal: Manage project memory with a database-backed system for decisions, tracking, and semantic search via a k
Stay ahead of the MCP ecosystem
Get weekly updates on new skills and servers.