App-Raider
view release on metacpan or search on metacpan
.claude/skills/perl-io-async-future/SKILL.md view on Meta::CPAN
}
```
Right:
```perl
sub _reconnect_attempt {
my ($self) = @_;
return if $self->{_connected};
weaken(my $weak = $self);
$self->{_reconnect_future} = $self->loop
->delay_future(after => $self->{reconnect_wait})
->then(sub {
my $self = $weak or return Future->done;
return Future->done if $self->{_connected};
return $self->connect;
})
->on_done(sub {
my $self = $weak or return;
.claude/skills/perl-io-async-future/SKILL.md view on Meta::CPAN
->on_fail(sub {
my $self = $weak or return;
delete $self->{_reconnect_future};
$self->_reconnect_attempt; # try again
});
}
```
**Rules:**
- Store the *whole chain* on the object (`$self->{_reconnect_future}`), not just the leaf.
- `weaken` `$self` inside callbacks â otherwise the chain holds the object alive forever.
- Always `delete $self->{_reconnect_future}` in both `on_done` and `on_fail`, or you'll guard out future reconnects with `return if $self->{_reconnect_future}`.
- On disconnect, **cancel the old `_connect_future`** so its async sub unwinds:
```perl
if (my $f = delete $self->{_connect_future}) {
$f->fail("disconnected: $reason") unless $f->is_ready;
}
```
---
.claude/skills/perl-io-async-future/SKILL.md view on Meta::CPAN
| Situation | Use |
|---|---|
| Subclassing IO::Async object | `parent 'IO::Async::Notifier'`, override `configure` |
| Storing async state on $self | `$self->{_foo_future}` â never bare lexicals |
| Sequential dependent ops | `->then` / `async`+`await` |
| Parallel, all required | `Future->needs_all` |
| First-to-finish race | `Future->wait_any` |
| Add timeout to op | `wait_any($op, $loop->delay_future(after=>N)->then_fail('timeout'))` |
| Side-effect observation | `->on_done` / `->on_fail` (don't chain) |
| Truly fire-and-forget | `->retain` (rare â usually you should hold it) |
| Closure capturing $self | `weaken(my $weak = $self)` + null-check inside |
| Cancelling stale attempt | `delete $self->{_f}; $f->cancel unless $f->is_ready` |
| Sync block-wait (tests/scripts) | `$f->get` |
---
## Common Pitfalls (the recurring ones)
- **Local-variable-only Future** â silent GC. Hold it on `$self`.
- **Async sub whose caller drops the Future** â "lost its returning future". Hold the result.
- **Strong `$self` capture in callback chain** â object never destroyed; reconnect loops leak. `weaken` it.
- **Forgetting to `delete` the held Future on completion** â stale guards block future operations.
- **Not chaining `SUPER::configure`** â defaults silently missing, or unknown keys silently accepted.
- **Returning a Future from `async sub` without `await`** â double-wrapped result.
- **Calling `$self->loop` before `$loop->add($self)`** â `loop` is undef.
- **Mixing `then` and `on_done` thinking they're the same** â `on_done` returns the original Future, your "chain" is actually two parallel observers.
- **Cancelling a Future inside its own callback** â undefined; cancel from outside.
- **Using `Future->new` instead of `$loop->new_future`** when you need loop-aware behavior (the loop variant integrates with timeouts and is the recommended form inside Notifier subclasses).
---
( run in 1.914 second using v1.01-cache-2.11-cpan-39bf76dae61 )