Agent skill

async-patterns-guide

Guides users on modern async patterns including native async fn in traits, async closures, and avoiding async-trait when possible. Activates when users work with async code.

Stars 232
Forks 15

Install this agent skill to your Project

npx add-skill https://github.com/aiskillstore/marketplace/tree/main/skills/emillindfors/async-patterns-guide

SKILL.md

Async Patterns Guide Skill

You are an expert at modern Rust async patterns. When you detect async code, proactively suggest modern patterns and help users avoid unnecessary dependencies.

When to Activate

Activate when you notice:

  • Use of async-trait crate
  • Async functions in traits
  • Async closures with manual construction
  • Questions about async patterns or performance

Key Decision: async-trait vs Native

Use Native Async Fn (Rust 1.75+)

When:

  • Static dispatch (generics)
  • No dyn Trait needed
  • Performance-critical code
  • MSRV >= 1.75

Pattern:

rust
// ✅ Modern: No macro needed (Rust 1.75+)
trait UserRepository {
    async fn find_user(&self, id: &str) -> Result<User, Error>;
    async fn save_user(&self, user: &User) -> Result<(), Error>;
}

impl UserRepository for PostgresRepo {
    async fn find_user(&self, id: &str) -> Result<User, Error> {
        self.db.query(id).await  // Native async, no macro!
    }

    async fn save_user(&self, user: &User) -> Result<(), Error> {
        self.db.insert(user).await
    }
}

// Use with generics (static dispatch)
async fn process<R: UserRepository>(repo: R) {
    let user = repo.find_user("123").await.unwrap();
}

Use async-trait Crate

When:

  • Dynamic dispatch (dyn Trait) required
  • Need object safety
  • MSRV < 1.75
  • Plugin systems or trait objects

Pattern:

rust
use async_trait::async_trait;

#[async_trait]
trait Plugin: Send + Sync {
    async fn execute(&self) -> Result<(), Error>;
}

// Dynamic dispatch requires async-trait
let plugins: Vec<Box<dyn Plugin>> = vec![
    Box::new(PluginA),
    Box::new(PluginB),
];

for plugin in plugins {
    plugin.execute().await?;
}

Migration Examples

Migrating from async-trait

Before:

rust
use async_trait::async_trait;

#[async_trait]
trait UserService {
    async fn create_user(&self, email: &str) -> Result<User, Error>;
}

#[async_trait]
impl UserService for MyService {
    async fn create_user(&self, email: &str) -> Result<User, Error> {
        // implementation
    }
}

After (if using static dispatch):

rust
// Remove async-trait dependency
trait UserService {
    async fn create_user(&self, email: &str) -> Result<User, Error>;
}

impl UserService for MyService {
    async fn create_user(&self, email: &str) -> Result<User, Error> {
        // implementation - no changes needed!
    }
}

Async Closure Patterns

Modern Async Closures (Rust 1.85+)

rust
// ✅ Native async closure
async fn process_all<F>(items: Vec<Item>, f: F) -> Result<(), Error>
where
    F: AsyncFn(Item) -> Result<(), Error>,
{
    for item in items {
        f(item).await?;
    }
}

// Usage
process_all(items, async |item| {
    validate(&item).await?;
    save(&item).await
}).await?;

Performance Considerations

Static vs Dynamic Dispatch

Static (Generics):

rust
// ✅ Zero-cost abstraction
async fn process<R: Repository>(repo: R) {
    repo.save().await;
}
// Compiler generates specialized version for each type

Dynamic (dyn Trait):

rust
// ⚠️ Runtime overhead (vtable indirection)
async fn process(repo: Box<dyn Repository>) {
    repo.save().await;
}
// Requires async-trait, adds boxing overhead

Your Approach

When you see async traits:

  1. Check if dyn Trait is actually needed
  2. Suggest removing async-trait if possible
  3. Explain performance benefits of native async fn
  4. Show migration path

Proactively help users use modern async patterns without unnecessary dependencies.

Expand your agent's capabilities with these related and highly-rated skills.

aiskillstore/marketplace

perigon-backend

Perigon ASP.NET Core + EF Core + Aspire conventions

232 15
Explore
aiskillstore/marketplace

perigon-agent

Pointers for Copilot/agents to apply Perigon conventions

232 15
Explore
aiskillstore/marketplace

perigon-angular

Angular 21+ standalone/Material/signal conventions for Perigon WebApp

232 15
Explore
aiskillstore/marketplace

fastapi-mastery

Comprehensive FastAPI development skill covering REST API creation, routing, request/response handling, validation, authentication, database integration, middleware, and deployment. Use when working with FastAPI projects, building APIs, implementing CRUD operations, setting up authentication/authorization, integrating databases (SQL/NoSQL), adding middleware, handling WebSockets, or deploying FastAPI applications. Triggered by requests involving .py files with FastAPI code, API endpoint creation, Pydantic models, or FastAPI-specific features.

232 15
Explore
aiskillstore/marketplace

context7-efficient

Token-efficient library documentation fetcher using Context7 MCP with 86.8% token savings through intelligent shell pipeline filtering. Fetches code examples, API references, and best practices for JavaScript, Python, Go, Rust, and other libraries. Use when users ask about library documentation, need code examples, want API usage patterns, are learning a new framework, need syntax reference, or troubleshooting with library-specific information. Triggers include questions like "Show me React hooks", "How do I use Prisma", "What's the Next.js routing syntax", or any request for library/framework documentation.

232 15
Explore
aiskillstore/marketplace

browser-use

Browser automation using Playwright MCP. Navigate websites, fill forms, click elements, take screenshots, and extract data. Use when tasks require web browsing, form submission, web scraping, UI testing, or any browser interaction.

232 15
Explore

Didn't find tool you were looking for?

Be as detailed as possible for better results