Dancer2-Plugin-DBIC-Async

 view release on metacpan or  search on metacpan

lib/Dancer2/Plugin/DBIC/Async.pm  view on Meta::CPAN

package Dancer2::Plugin::DBIC::Async;

$Dancer2::Plugin::DBIC::Async::VERSION   = '0.06';
$Dancer2::Plugin::DBIC::Async::AUTHORITY = 'cpan:MANWAR';

use strict;
use warnings;
use feature 'state';

use Dancer2::Plugin;
use IO::Async::Loop;
use DBIx::Class::Async::Schema;
use Module::Runtime qw(use_module);

=encoding utf8

=head1 NAME

Dancer2::Plugin::DBIC::Async - High-concurrency DBIx::Class bridge for Dancer2

=head1 VERSION

Version 0.06

=head1 BENEFITS

The primary benefit of this plugin is B<Concurrency Throughput>. Unlike traditional
database plugins that block your Dancer2 worker during a query, this plugin
delegates I/O to a background worker pool.

=head2 Non-Blocking I/O (Concurrency)

In a traditional sync app, if a database query takes B<500ms>, that L<Dancer2>
worker is B<"busy"> and cannot accept any other incoming requests for that
B<half a second>.

=over 4

=item Sync

B<10 workers> can handle exactly B<10 simultaneous long-running queries>. The
11th user must wait in the B<TCP queue>.

=item Async

A single worker can initiate dozens of database queries. While the database is
processing the data, the worker remains free to handle other incoming requests
or perform other I/O tasks.

=back

=head2 Parallelism within a Single Route

With the sync plugin, if you need to fetch data from five different tables that don't depend on
each other, you must do them sequentially. With the async plugin, you can fire all five queries
simultaneously.

    # Regular Sync (Total time = sum of all queries)
    my $user    = rset('User')->find(1);
    my $posts   = rset('Post')->search({ uid => 1 });
    my $friends = rset('Friend')->search({ uid => 1 });

    # Async (Total time = the time of the single slowest query)
    my $user_f    = async_rs('User')->find(1);
    my $posts_f   = async_rs('Post')->search({ uid => 1 });
    my $friends_f = async_rs('Friend')->search({ uid => 1 });

    # Wait for all to finish
    my ($user, $posts, $friends) = Future->wait_all($user_f, $posts_f, $friends_f)->get;

=head2 Key Technical Differences

=over 4

=item B<Context Switching>

In the sync version, the operating system might pause the process (context switch)
while waiting for the disk. In the async version, the Event Loop (L<IO::Async>) manages
this, which is much lighter on the CPU.

=item B<Wait vs. Block>

In the async version, we use B<wait_all> or B<then>. This tells the server:
B<"Keep this request in mind, but go help other users until the data comes back.">

=item B<Error Handling>

L<Futures> have built-in B<on_fail> handlers, making it easier to manage database
timeouts without crashing the whole worker process.

=back

=head2 Better Resource Utilisation



( run in 0.921 second using v1.01-cache-2.11-cpan-39bf76dae61 )