USP
It uniquely integrates AI assistance directly into the Armeria development lifecycle, offering specialized skills for tasks like performance auditing and release management that are deeply aware of Armeria's architecture and best practices.
Use cases
- 01Developing and maintaining Armeria microservices
- 02Automating release note generation and dependency upgrades
- 03Auditing Armeria projects for event loop blocking issues
- 04Debugging performance and concurrency problems in Armeria services
Detected files (4)
.claude/skills/release-note/SKILL.mdskillShow content (10254 bytes)
--- name: release-note description: Generate and polish release notes for an Armeria version. Runs site-new/release-note.ts to collect PR data from a GitHub milestone, then rewrites the skeletal output into publication-ready MDX. Invoked as `/release-note <version>` (e.g., `/release-note 1.38.0`). --- # Release Note Generator Generates skeletal release notes from a GitHub milestone using `site-new/release-note.ts`, then rewrites them into polished, publication-ready MDX with rich descriptions, code examples, and proper formatting. ## Prerequisites - The `gh` CLI must be authenticated with access to `line/armeria`. Verify with `gh auth status`. - A `GITHUB_ACCESS_TOKEN` environment variable is recommended for higher GitHub API rate limits. If not set, the script falls back to anonymous access (lower rate limits). - Node.js and npm must be available. The `site-new/` directory must have dependencies installed (`npm install` in `site-new/`). ## Invocation ``` /release-note <version> ``` Example: `/release-note 1.38.0` --- ## Phase 0: Generate Skeletal Release Notes 1. Verify the GitHub milestone exists for the given version by checking: ``` gh api repos/line/armeria/milestones --jq '.[] | select(.title == "<version>") | .number' ``` 2. Run the release note generation script: ``` cd site-new && npm run release-note <version> ``` 3. Verify the output file was created at `site-new/src/content/release-notes/<version>.mdx`. 4. If the script fails (e.g., milestone not found, network error), report the error and stop. ## Phase 1: Load Draft and Study Style 1. Read the generated draft file at `site-new/src/content/release-notes/<version>.mdx`. 2. Read 3-4 recent polished release notes (e.g., `1.36.0.mdx`, `1.37.0.mdx`) to calibrate tone and style. 3. Read the style guide at `references/style-guide.md` for formatting rules. 4. Extract all PR/issue references (`#NNNN`) from every line of the draft. ## Phase 2: Gather PR Context from GitHub For each unique PR number found in the draft: 1. Fetch PR details: ``` gh pr view <number> --repo line/armeria --json title,body,labels,files ``` 2. Parse the PR body to extract **Motivation**, **Modifications**, and **Result** sections. 3. Fetch PR review comments — these often contain important design decisions, caveats, and scope limitations (e.g., "this only applies to unary calls") that are not in the PR description: ``` gh api repos/line/armeria/pulls/<number>/comments --jq '.[].body' ``` 4. Extract linked issue numbers from the body (`Closes #NNNN`, `Fixes #NNNN`, `Resolves #NNNN`). 5. For each linked issue, fetch its context **including comments**, which often contain use cases, edge cases, and design discussions that inform the release note description: ``` gh issue view <number> --repo line/armeria --json title,body gh api repos/line/armeria/issues/<number>/comments --jq '.[].body' ``` 6. For PRs in the "New features" section that introduce significant new API: - Read key changed source files from the PR's `files` list to understand method signatures. - Look for usage examples in the PR description's Result section first — prefer these over constructing examples from scratch. - Check review comments for scope limitations, caveats, or known constraints that should be mentioned in the release note (e.g., "only supports unary methods", "HTTP/2 only"). **Rate limiting**: If fetching many PRs, batch requests and pause briefly between them to avoid GitHub API rate limits. ## Phase 3: Triage "Maybe Ignore" Section The script puts PRs without a recognized label into `🗑 Maybe ignore`. For each entry: 1. Check the PR's labels and description. 2. **Drop** items that are purely internal (CI config, build scripts, test infrastructure, non-user-facing refactoring, site/docs dependency bumps). 3. **Relocate** user-facing items to the correct section based on their actual impact: - API additions → New features - Performance or usability improvements → Improvements - Bug fixes → Bug fixes - Breaking API changes → Breaking changes 4. Report triage decisions to the user so they can override if needed. ## Phase 4: Rewrite Each Section Rewrite every entry following the formatting rules in `references/style-guide.md`. ### Ordering 1. **Lead with user interest**: Place the top 3 entries that users would care about most first. Prioritize broadly applicable features (core, gRPC, Kubernetes) over niche modules (Athenz, xDS). Consider the size of the user base affected and how common the use case is. 2. **Then group by module**: After the top 3, group remaining entries by module/area so that related changes appear together (e.g., Athenz entries adjacent, Kubernetes entries adjacent). 3. This applies to all sections (New features, Improvements, Bug fixes, etc.). ### Key principles: ### New Features (`🌟 New features`) - All new feature entries get a bold title prefix: `- **Feature Title**: Description. #NNNN` - **Keep descriptions concise** — most entries should fit within 3 lines of prose. Only high-impact features (e.g., a brand-new module or paradigm-shifting API) warrant longer descriptions. - Include a Java code example (5-15 lines) whenever possible. It may be omitted if there is no clear usage pattern to show. - Mark the most important line with `// 👈👈👈` - Indent code blocks with 2 spaces under the bullet. ### Improvements (`📈 Improvements`) - Concise description of what improved and why it matters. - Code examples only if the improvement changes how users interact with an API. ### Bug Fixes (`🛠️ Bug fixes`) - Describe the symptom that was fixed, not the internal cause. - Format: "[What was broken] now [works correctly]. #NNNN" ### Breaking Changes (`☢️ Breaking changes`) - State clearly what changed and what users must do to migrate. - Include before/after code if the migration is non-trivial. ### Documentation (`📃 Documentation`) - Brief description with links to the new/updated docs if available. ### Deprecations (`🏚️ Deprecations`) - State what is deprecated and what to use instead. ### All Sections — Common Rules - Use `[ClassName](type)` for Armeria API types (classes, interfaces, annotations, methods). - For classes/interfaces: `[GrpcServiceBuilder](type)` - For methods: `[GrpcServiceBuilder#enableEnvoyHttp1Bridge(boolean)](type)` — always include the class name, method name, and parameter types. Do NOT use backtick-only style like `` `enableEnvoyHttp1Bridge(true)` `` for Armeria public API references in prose. - Do NOT use this syntax for JDK types (`String`, `Duration`, `CompletableFuture`), third-party types, or types that are not part of Armeria's public API. - Issue and PR references go at the end of the entry: `#6431 #6691` (list both the issue and the PR) - Do NOT copy PR titles verbatim — they are often terse commit-style messages. - Do NOT fabricate code examples. Derive them from PR descriptions or actual source code. - Keep entries self-contained — a reader should understand the change without clicking the PR link. ## Phase 5: Clean Up Dependencies Section The raw script includes the full dependency update PR body, which uses a structured commit message format. 1. **Strip build-only dependencies**: Remove the `- Build` section and all its sub-bullets (these are testImplementation, annotationProcessor, and other non-production deps). 2. **Format each entry**: `- LibraryName oldVersion → newVersion` - Use the library's common name (e.g., `Jackson`, `Netty`, `gRPC-Java`, not the Maven artifact ID). - Use `→` (unicode arrow), not `->`. 3. **Group multi-version bumps** on one line when a library has multiple version streams: `- Spring 6.2.14 → 6.2.15, 7.0.2 → 7.0.3` 4. **Sort alphabetically** (A → Z). ## Phase 6: Finalize 1. **Remove empty sections**: Delete any section whose only content is `- N/A`. 2. **Remove "Maybe ignore"**: The `🗑 Maybe ignore` section must not appear in the final output. 3. **Deduplicate and sort contributors**: Ensure `<ThankYou usernames={[...]} />` has alphabetically sorted, deduplicated usernames. Remove bot accounts (`dependabot[bot]`, `CLAassistant`). Core maintainers listed in `.github/CODEOWNERS` must always be included in the Thank You section, even if they don't appear in the PR participant lists. 4. **Ensure consistent bullet style**: Use `-` (dash) for all bullets, not `*`. 5. **Write the final file** to `site-new/src/content/release-notes/<version>.mdx`. 6. **Show a summary** to the user: list the sections, entry count per section, and any entries flagged as uncertain (where PR context was insufficient to write a confident description). --- ## Execution Checklist - [ ] Phase 0 — Ran `npm run release-note <version>` and verified output file exists - [ ] Phase 1 — Read draft, recent examples, and style guide - [ ] Phase 2 — Fetched PR/issue context for all referenced PRs - [ ] Phase 3 — Triaged all "Maybe ignore" entries - [ ] Phase 4 — Rewrote all entries per style guide - [ ] Phase 5 — Cleaned up dependencies section - [ ] Phase 6 — Removed empty sections, finalized file, reported summary ## Common Mistakes to Avoid - **Copying PR titles as-is**: PR titles like "Fix NPE in FooBar" are not user-friendly. Rewrite as "Fixed a `NullPointerException` in [FooBar](type) when ..." - **Fabricating code examples**: If you cannot find a clear usage pattern from the PR description or source code, write a descriptive sentence instead of guessing at code. - **Over-linking types**: Only use `[Name](type)` for Armeria's own public API types, not for JDK classes, third-party libraries, or internal classes. - **Including build dependencies**: The dependency update PR body contains `- Build` sub-bullets for test/build-only deps. These must be stripped. - **Leaving `- N/A` sections**: The polished output should only contain sections with actual content. - **Using `*` bullets**: Standardize on `-` dashes for all bullet points. - **Missing `👈👈👈` callouts**: Every code example for a new feature should highlight the key line..claude/skills/upgrade-deps/SKILL.mdskillShow content (6431 bytes)
--- name: upgrade-deps description: Upgrade Gradle dependencies and Gradle wrapper version disable-model-invocation: true --- # Dependency Upgrade Workflow This skill performs a full Gradle dependency upgrade for the Armeria project step by step. ## Background: Minimum Java Version Per Module Armeria is a multi-module project with different minimum Java version requirements. Before upgrading a dependency, always verify that the new version supports the minimum Java version required by the modules that use it. | Java Version | Modules | |-------------|---------| | **8** | `core`, `brave5`, `brave6`, `eureka`, `grpc`, `grpc-kotlin`, `graphql-protocol`, `jetty9`, `junit4`, `junit5`, `kafka`, `kotlin`, `logback`, `logback12`, `logback13`, `micrometer-context`, `oauth2`, `prometheus1`, `protobuf`, `reactor3`, `resteasy`, `retrofit2`, `rxjava2`, `rxjava3`, `sangria`, `scala*`, `spring:boot2-*`, `dropwizard2`, `thrift0.9`–`thrift0.17`, `tomcat8`, `tomcat9`, `xds`, `zookeeper3`, `saml`, `bucket4j`, `consul`, `nacos` | | **11** | `athenz`, `graphql`, `jetty10`, `jetty11`, `kubernetes`, `logback14`, `thrift0.18`–`thrift0.22`, `tomcat10` | | **17** | `ai:mcp`, `jetty12`, `resilience4j2`, `spring:boot3-*`, `spring:spring6`, `spring:boot4-*`, `spring:spring7` | When in doubt, check `settings.gradle` for the `java`, `java11`, or `java17` flag on each subproject. ## Step 1: Run dependencyUpdates ``` ./gradlew dependencyUpdates ``` The report is saved to `build/dependencyUpdates/report.txt`. ## Step 2: Parse the Report Read `build/dependencyUpdates/report.txt` to identify all outdated dependencies. For each dependency, note the current version and the available latest version. If a version looks ambiguous (unexpected format, major version bump, unusual naming), verify on Maven Central before proceeding: https://central.sonatype.com/artifact/{groupId}/{artifactId} ## Step 3: Check Skip Hints and Java Version Compatibility Before upgrading any dependency, check `dependencies.toml` for a comment directly above its version entry. Many pinned versions have an explicit reason, for example: ```toml # Don't upgrade Caffeine to 3.x that requires Java 11. caffeine = "2.9.3" # Upgrade once https://github.com/ronmamo/reflections/issues/279 is fixed. reflections = "0.9.11" # Ensure that we use the same ZooKeeper version as what Curator depends on. zookeeper = "3.9.3" ``` If such a comment exists and the reason still applies, **skip the upgrade** and do not remove the comment. If no comment exists, proceed with the Java version compatibility check: 1. Find which modules use this dependency in `dependencies.toml` 2. Determine the minimum Java version required by those modules (see table above) 3. Check the new library version's minimum Java requirement (Maven Central / release notes) 4. If the library's required Java > module's minimum Java → **skip the upgrade** and add a comment above the version entry explaining why (e.g. `# X.Y requires Java 11`) 5. If compatible → proceed with the upgrade ## Step 4: Update dependencies.toml Edit the `[versions]` section in `dependencies.toml` to update the version strings. The file is located at the root of the repository: `dependencies.toml`. ## Step 5: Cross-check Updated Versions After editing `dependencies.toml`, re-read the full diff (`git diff dependencies.toml`) and cross-check every changed entry against the `dependencyUpdates` report: 1. **No entry was accidentally skipped** — compare the report's "The following dependencies have later milestone versions" list against your edits. If a dependency appears in the report but not in the diff, either upgrade it or document why it was skipped. 2. **Versions match the report** — confirm each new version in the diff matches the latest version from the report, not a typo or intermediate version. 3. **Pinned-version comments were respected** — verify you did not upgrade a dependency whose comment says to skip it, and that you did not remove or contradict an existing comment. 4. **Linked-version constraints are satisfied** — some dependencies must stay in sync with others (e.g. ZooKeeper with Curator, Protobuf with gRPC). Read the comments above those entries and verify the constraint still holds after the upgrade. ## Step 6: Upgrade Gradle Wrapper Check the latest stable Gradle release at https://gradle.org/releases/ and update `gradle/wrapper/gradle-wrapper.properties`: ```properties distributionUrl=https\://services.gradle.org/distributions/gradle-X.Y.Z-all.zip ``` ## Step 7: Verify the Build Run the full build including tests to catch both compilation errors and runtime regressions: ``` ./gradlew build --no-daemon ``` If there are compilation errors, API breaking changes, or test failures caused by the upgrade, fix them before proceeding. ## Step 8: Commit Create a commit with the **exact** message format below. Follow it strictly — do not add extra sections, reorder bullets, or change the structure: ``` Update dependencies - {library-name} {old-version} -> {new-version} - {library-name} {old-version} -> {new-version} - Build - {library-name} {old-version} -> {new-version} - {library-name} {old-version} -> {new-version} ``` Rules: - Each production dependency (api/implementation scope) gets one bullet: `- {name} {old} -> {new}` - The `- Build` bullet groups build-only dependencies (testImplementation, annotationProcessor, relocated libs, non-transitive deps); nest them as sub-bullets with 3-space indent - Use the library's official name if one exists (e.g. `gRPC-Java`, `Jackson`, `Netty`, `Kotlin`, `Reactor`, `Logback`, `Micrometer`); otherwise use the key name as-is from `dependencies.toml` - Sort entries **alphabetically (A → Z)** within each section - If no build-only deps were upgraded, omit the `- Build` section entirely - If any dependencies were **not upgraded** (due to Java version constraints, pinned-version comments, or linked-version constraints), list them under a `- Unupdated` section with the reason. This helps reviewers know which upgrades were intentionally skipped. Example: ``` Update dependencies - gRPC-Java 1.63.0 -> 1.64.0 - Jackson 2.17.0 -> 2.18.0 - Build - checkstyle 10.14.0 -> 10.17.0 - ErrorProne 2.27.0 -> 2.28.0 - Unupdated - Caffeine 2.9.3 -> 3.2.0 (requires Java 11) - ZooKeeper 3.9.3 (pinned to Curator's version) ```tools/claude-plugins/assistant/skills/eventloop-audit/SKILL.mdskillShow content (15536 bytes)
--- name: eventloop-audit description: Systematically audits any Armeria-based Java project for event loop blocking issues — discovers project patterns, scans for blocking operations, traces call chains, and produces a fix plan without modifying code. Use when experiencing latency spikes, connection timeouts, deadlocks, or thread starvation in Armeria services, or as a pre-release audit. Invoked as `/eventloop-audit` for the full project or `/eventloop-audit <path>` for a specific directory. --- # Event Loop Blocking Audit for Armeria Projects ## Overview A systematic, multi-phase audit that discovers how a project uses Armeria, scans for all categories of event loop blocking, traces call chains to determine thread context, and produces a structured report with fix plans. **No code is modified** — only analysis and planning. This skill is **framework-generic** — it works on any Armeria-based Java project by discovering the project's patterns dynamically, not assuming specific class names or directory structures. ## When to Use - After setting up a new Armeria-based project and want to verify thread safety - Before a release to audit for latent event loop blocking issues - When experiencing unexplained latency spikes, connection timeouts, or deadlocks in an Armeria server - After integrating a new library that may contain blocking calls - As a periodic health check on the codebase's non-blocking discipline ## Thread Model Reference For a comprehensive guide on Armeria's thread pools, executor selection, and programmatic usage patterns, see [armeria-thread-pool-guide.md](references/armeria-thread-pool-guide.md). **The Golden Rule**: If `Thread.currentThread() instanceof NonBlocking` — you **MUST NOT** block. Armeria's event loop threads implement the `NonBlocking` marker interface. Any blocking operation on these threads stalls ALL connections sharing that event loop, causing cascading latency and potential deadlocks. --- ## Phase 1: Discovery — Understand the Project's Armeria Usage Before searching for problems, discover HOW the project uses Armeria. Launch an **Explore agent** (or do it yourself) with these specific searches. Record findings as they'll inform all subsequent phases. ### 1.1 Find Armeria Server Configuration ```text Grep: Server\.builder\(\)|ServerBuilder Scope: **/*.java ``` Read each match and document: - Worker group configuration (`workerGroup(n)`, `serviceWorkerGroup(n)`) - Blocking executor configuration (`blockingTaskExecutor(...)`) - Decorator chain (`.decorate(...)` calls) - Request/idle timeout settings - Any custom `EventLoopGroup` creation ### 1.2 Find HttpService Implementations ```text Grep: implements HttpService|extends AbstractHttpService|extends SimpleDecoratingHttpService Scope: **/*.java ``` These classes have `serve()` methods that run on the event loop. List all of them — they are the primary audit targets. ### 1.3 Find Annotated Services ```text Grep: @Get\(|@Post\(|@Put\(|@Delete\(|@Head\(|@Patch\(|@Options\( Scope: **/*.java ``` For each, check if the method or class has `@Blocking`. Methods without `@Blocking` run on the event loop. ### 1.4 Find gRPC Services ```text Grep: extends \w+ImplBase|GrpcService\.builder\(\) Scope: **/*.java ``` Check whether `useBlockingTaskExecutor(true)` is configured in the `GrpcService.builder()`. If not, all gRPC handler methods run on the event loop. ### 1.5 Find Thrift Services ```text Grep: THttpService\.builder\(\)|THttpService\.of\( Scope: **/*.java ``` Same check — look for `useBlockingTaskExecutor(true)`. ### 1.6 Find Decorators ```text Grep: SimpleDecoratingHttpService|DecoratingHttpServiceFunction|\.decorate\( Scope: **/*.java ``` Every decorator's `serve()` method runs on the event loop. List them all. ### 1.7 Find Custom Executors and Thread Pools ```text Grep: blockingTaskExecutor\(\)|ctx\.eventLoop\(\)|Executors\.new|new ThreadPoolExecutor|new ForkJoinPool|ExecutorService Scope: **/*.java ``` Document all custom thread pools and how they're used. These are the "safe zones" where blocking is OK. ### 1.8 Find Offloading Patterns ```text Grep: supplyAsync|thenApplyAsync|thenComposeAsync|thenAcceptAsync|ctx\.blockingTaskExecutor|makeContextAware Scope: **/*.java ``` Understand the project's conventions for offloading work from the event loop. Look for: - **Base class methods** that submit work to a blocking executor (e.g., a `runBlocking(Supplier)` method in a base handler) - **Utility classes** that wrap `ctx.blockingTaskExecutor()` with additional logic (cancellation, metrics, tracing) - **Project-specific annotations** that trigger blocking executor dispatch (beyond Armeria's `@Blocking`) A wrapper is "safe" if it provably submits the lambda/callable to a non-event-loop executor before the lambda body executes. Read the wrapper's implementation to verify — don't trust method names alone. ### 1.9 Build Architecture Map Synthesize findings into a concise map: - **Event loop entry points**: List of classes/methods where the event loop calls into application code - **Safe execution wrappers**: Project-specific methods that offload to blocking executors - **Thread pool inventory**: All thread pools, their sizing, and purpose - **Decorator chain**: The order in which decorators wrap services --- ## Phase 2: Systematic Detection — 7 Categories Search the entire project (or scoped path) for each category of blocking pattern. Exclude test files (`**/test/**`, `**/tests/**`) and generated code (`**/generated/**`, `**/target/**`, `**/build/**`). See [detection-patterns.md](references/detection-patterns.md) for the complete search patterns and triage guidance for all 7 categories: 1. **Direct Blocking Calls** — `.join()`, `.get()`, `Thread.sleep()`, `.await()`, `.lock()`, etc. 2. **Blocking I/O Operations** — File I/O, network, JDBC, serialization, encryption 3. **Synchronization** — `synchronized`, `ReentrantLock`, `StampedLock` on request paths 4. **CompletableFuture Continuations on Wrong Executor** — `.thenApply()` without `Async` where completing thread is event loop 5. **Thread Pool Misconfiguration** — Unbounded pools, missing shutdown, undersized blocking executor 6. **Missing Armeria Idioms** — Missing `@Blocking`, missing `useBlockingTaskExecutor(true)`, blocking cancel handlers, missing context propagation 7. **Transitive / Hidden Blocking** — DNS resolution, class loading, synchronous logging appenders --- ## Phase 3: Call Chain Analysis For each finding from Phase 2, perform call chain analysis to determine the thread context. ### Analysis Steps 1. **Identify enclosing method** — What method contains the potentially blocking call? 2. **Find all callers** — Grep for the method name across the project: ```text Grep: methodName\( Scope: **/*.java ``` When handling overloaded methods (same name, different signatures), read each call site to confirm it calls the blocking variant. Also check superclass/interface hierarchies — a `serve()` override in a subclass is still called from the event loop if the parent is an `HttpService`. 3. **Trace to entry point** — Follow the call chain upward until you reach one of: - An Armeria entry point (`serve()`, `@Get`/`@Post` handler, gRPC handler, decorator) - A thread pool submission (`blockingTaskExecutor().execute(...)`, `supplyAsync(...)`, etc.) - A framework callback (`whenRequestCancelling`, `setOnCancelHandler`) - A lambda/method reference passed to an executor (`.submit(this::methodName)`) **Handling ambiguity**: If a method is called from BOTH event loop paths AND thread pool paths, classify based on the worst case (event loop path). Note both paths in the finding. 4. **Determine thread context** — At the entry point: - Is there a `@Blocking` annotation? → Safe - Is there `useBlockingTaskExecutor(true)`? → Safe - Is it inside a `supplyAsync(..., blockingExecutor)` call? → Safe - Is it inside a project-specific safe wrapper (discovered in Phase 1.8)? → Safe - None of the above? → **Event loop** 5. **Classify severity using this decision tree:** ```text Is the blocking call provably inside a blocking executor or thread pool? ├── YES → SAFE (exclude from report or list separately) ├── NO, it's provably on the event loop: │ ├── Is it an I/O operation, .join(), .get() without timeout, or Thread.sleep()? │ │ └── YES → CRITICAL │ ├── Is it .get(timeout, unit) or .await(timeout, unit)? │ │ └── YES → HIGH (blocks event loop for the timeout duration) │ ├── Is it a synchronized block or lock? │ │ ├── Can it contend with a thread that holds the lock for >1ms? │ │ │ └── YES → HIGH │ │ └── Low contention, very fast critical section? │ │ └── LOW │ └── Is it a very fast operation (System.getProperty, in-memory map lookup)? │ └── LOW └── UNDETERMINED (e.g., CF continuation where completing thread varies): ├── Could the continuation body block? │ ├── YES → MEDIUM (must verify at runtime or refactor to be safe) │ └── NO (continuation is pure computation) → LOW └── Is the source future always completed by a thread pool? └── YES → SAFE ``` **Key distinction**: MEDIUM means "we cannot statically prove the thread context" — it requires either runtime verification (add logging/assertion) or defensive refactoring (use `*Async` variant with explicit executor). --- ## Phase 4: Fix Plan Templates For each non-SAFE finding, recommend one of the fix approaches documented in [fix-templates.md](references/fix-templates.md): | Template | When to use | |----------|-------------| | **FP-1** | Replace `.join()`/`.get()` with async chaining | | **FP-2** | Offload blocking work to `ctx.blockingTaskExecutor()` | | **FP-3** | Add `@Blocking` annotation to annotated service methods | | **FP-4** | Enable `useBlockingTaskExecutor(true)` for gRPC/Thrift services | | **FP-5** | Use `*Async` CF variant with explicit executor | | **FP-6** | Add timeout to unavoidable blocking | | **FP-7** | Make thread pool initialization thread-safe | | **FP-8** | Wire context propagation with `makeContextAware` | **Document the recommendation — do not apply it.** --- ## Phase 5: Produce the Report ### Per-Finding Format ```markdown ## Finding [ID]: [Short descriptive title] **Severity**: CRITICAL / HIGH / MEDIUM / LOW **File**: [relative path]:[line number] **Thread context**: Event loop / Blocking executor / Undetermined **Detection category**: [1-7 with category name] ### Description [What the code does and why it's a blocking risk on the event loop] ### Call chain [Armeria entry point (event loop)] → [Method A] → [Method B] → [blocking call at line X] ### Recommended fix [Reference FP-1 through FP-8, with specific application to this case: which method to change, what the new code should look like, which executor to use] ### Risk assessment [What could break when applying the fix, edge cases to consider, tests to run] ``` ### Summary Table At the end of all findings, produce a summary: ```markdown | # | Severity | File | Line | Category | Blocking Pattern | Fix | |---|----------|------|------|----------|-----------------|-----| | 1 | CRITICAL | FooService.java | 42 | 1 - Direct blocking | `.join()` | FP-1 | | 2 | HIGH | BarHandler.java | 88 | 2 - I/O | FileInputStream | FP-2 | | ... | ... | ... | ... | ... | ... | ... | ``` ### Statistics ```markdown - Total findings: [N] - CRITICAL: [N] | HIGH: [N] | MEDIUM: [N] | LOW: [N] | SAFE (excluded): [N] - By category: Cat.1: [N] | Cat.2: [N] | Cat.3: [N] | Cat.4: [N] | Cat.5: [N] | Cat.6: [N] | Cat.7: [N] ``` ### Follow-Up Recommendations Always include these recommendations regardless of findings: 1. **Runtime detection**: Consider adding [BlockHound](https://github.com/reactor/BlockHound) to the test suite — it detects blocking calls on non-blocking threads at runtime 2. **Async logging**: Verify that the logging framework uses async appenders in production to avoid blocking on `log.*()` calls 3. **Event loop monitoring**: Enable Armeria's built-in event loop blocking detection: ```text -Dcom.linecorp.armeria.reportBlockedEventLoop=true ``` 4. **Code review checklist**: Add "Does this handler offload blocking work?" to the team's code review checklist for Armeria services --- ## Execution Checklist Follow this checklist to ensure nothing is skipped. Check off each item as you complete it. ### Phase 1: Discovery - [ ] 1.1 — Found and documented Armeria server configuration(s) - [ ] 1.2 — Listed all `HttpService` implementations - [ ] 1.3 — Listed all annotated services, noted `@Blocking` presence/absence - [ ] 1.4 — Listed all gRPC services, noted `useBlockingTaskExecutor` presence/absence - [ ] 1.5 — Listed all Thrift services (if any) - [ ] 1.6 — Listed all decorators - [ ] 1.7 — Documented all custom executors and thread pools - [ ] 1.8 — Identified project-specific offloading patterns - [ ] 1.9 — Built architecture map (entry points, safe wrappers, thread pools) ### Phase 2: Detection - [ ] Category 1 — Searched for all direct blocking calls - [ ] Category 2 — Searched for all blocking I/O operations - [ ] Category 3 — Searched for synchronization on request paths - [ ] Category 4 — Audited CompletableFuture continuation executors - [ ] Category 5 — Audited thread pool configurations - [ ] Category 6 — Checked for missing Armeria idioms (@Blocking, useBlockingTaskExecutor, cancel handlers, context propagation) - [ ] Category 7 — Searched for transitive/hidden blocking (DNS, class loading, logging config) ### Phase 3: Analysis - [ ] Traced call chains for ALL non-obvious findings - [ ] Classified every finding by severity - [ ] Excluded SAFE findings from the report (or listed them separately) ### Phase 4: Fix Planning - [ ] Assigned a fix template (FP-1 through FP-8) to each non-SAFE finding - [ ] Documented specific fix details for each finding ### Phase 5: Reporting - [ ] Produced per-finding reports - [ ] Produced summary table - [ ] Produced statistics - [ ] Included follow-up recommendations --- ## Common Mistakes to Avoid - **Stopping at grep hits** — A grep hit is not a finding. You must trace the call chain to determine thread context. Many `.join()` calls are inside thread pool code and are perfectly safe. - **Ignoring non-async CF continuations** — `.thenApply()` without `Async` is the most subtle source of event loop blocking. The continuation runs on whatever thread completes the source future. - **Missing cancel handlers** — Cancel handler lambdas always run on the event loop. They're easy to overlook but are a common source of blocking. - **Assuming `synchronized` is always bad** — It's only a problem if (a) it's on a request path reachable from the event loop AND (b) the lock can be contended by another thread holding it for a long time. - **Forgetting transitive blocking** — A clean `serve()` method that calls `helperMethod()` which calls `utilMethod()` which calls `.join()` is still blocking the event loop. - **Ignoring logging** — If the logging framework uses synchronous file appenders, every `log.info()` on the event loop is a blocking I/O operation. This is a configuration issue, not a code issue, but still critical..claude-plugin/marketplace.jsonmarketplaceShow content (444 bytes)
{ "name": "armeria", "owner": { "name": "armerian", "email": "dl_armeria@linecorp.com" }, "metadata": { "description": "Claude plugin for the Armeria microservice framework", "version": "0.0.1" }, "plugins": [ { "name": "assistant", "source": { "source": "git-subdir", "url": "https://github.com/line/armeria.git", "path": "tools/claude-plugins/assistant" } } ] }
README
Visit the official web site for more information.
Armeria
Build a reactive microservice at your pace, not theirs.
Armeria is your go-to microservice framework for any situation. You can build any type of microservice leveraging your favorite technologies, including gRPC, Thrift, Kotlin, Retrofit, Reactive Streams, Spring Boot and Dropwizard.
It is open-sourced by the creator of Netty and his colleagues at LINE Corporation.
Requirements
- Java 8 or later if you are a user.
- See the developer guide if you are building Armeria.
How to reach us — chat, questions and newsletters
Visit the community to chat with us, ask questions and learn how to contribute.
Hall of fame
See the complete list of our contributors.