DBIx-QuickORM

 view release on metacpan or  search on metacpan

lib/DBIx/QuickORM/Manual/Async.pm  view on Meta::CPAN

package DBIx::QuickORM::Manual::Async;
use strict;
use warnings;

our $VERSION = '0.000022';

1;

__END__

=head1 NAME

DBIx::QuickORM::Manual::Async - Asynchronous, aside, and forked queries in
L<DBIx::QuickORM>.

=head1 DESCRIPTION

Most queries in L<DBIx::QuickORM> are synchronous: you call a fetch method on a
L<DBIx::QuickORM::Handle> and it blocks until the database returns. Sometimes
you want to fire a query off and keep working while the database does its job.
This guide covers the three ways to do that - C<async>, C<aside>, and
C<forked> - what each one means, when to reach for it, and the rules you must
follow.

All three are selected on a handle and are mutually exclusive; asking for more
than one at once is an error. See L<DBIx::QuickORM::Handle> for the handle API
and L<DBIx::QuickORM::Connection> for the connection that owns these queries.

=head1 THE THREE MODES

=head2 async - driver-level asynchronous

    my $h = $orm->handle('events', {processed => 0});
    my $iter = $h->async->iterator;    # query is sent, does not block

This uses the database driver's own asynchronous support. The query runs on
your B<primary> connection while your code keeps going. It is the cheapest
option - no extra connection, no extra process - but it has the strictest
constraints (see L</"RULES AND CONSTRAINTS"> below), because the one connection
is busy until the query finishes.

Not every database supports this. If the dialect does not advertise async
support (for example L<DBD::SQLite>), selecting C<async> and running a query
throws an exception. Use C<forked> instead on those backends.

=head2 aside - asynchronous on a separate connection

    my $iter = $h->aside->iterator;

An C<aside> query is the same driver-level async mechanism, but run on a
B<separate> connection obtained from the ORM rather than on your primary
connection. Because the primary connection stays free, an aside query does
B<not> block other work on it: you can run normal synchronous queries, open
transactions, and even start more aside or forked queries while it is in
flight.

Reach for C<aside> when you want async behavior but do not want to tie up your
main connection. It still requires a driver that supports async.

=head2 forked - run the query in a child process

    my $iter = $h->forked->iterator;

A C<forked> query C<fork()>s a child process with its own database connection,
runs the query there, and streams the results back to the parent. The parent
never blocks while the child works.

This is the way to get asynchronous behavior on databases whose driver has no
native async support, such as SQLite. Like C<aside>, it runs off your primary
connection, so it does not block it.

The results cross from child to parent over a pipe (via L<Atomic::Pipe>) with
C<zstd> compression, so more rows fit in the pipe buffer and less data hits the
wire. You do not interact with the transport directly - you just pull rows.

=head1 RUNNING AN ASYNC QUERY

The pattern is the same for all three modes. Pick the mode, get an
L<DBIx::QuickORM::Iterator>, poll C<ready()>, then drain the results:

    my $iter = $h->async->iterator;    # or ->aside->iterator / ->forked->iterator

    until ($iter->ready) {
        do_something_useful();          # the DB is working in the background
    }

    while (my $row = $iter->next) {
        ...                             # rows arrive here
    }

C<ready()> is non-blocking: it polls and returns true once results are
available (for a synchronous handle it is always true). C<next()> pulls one row
at a time; if results have not arrived yet it blocks until they do.

C<all()>, C<count()>, C<iterate()>, and C<first()>/C<one()> in C<data_only>
mode are B<not> available on an async handle - C<all()> in particular would
have to block, defeating the purpose. Use C<iterator()> and its C<ready()>
method instead.

=head2 Single-row async results



( run in 0.411 second using v1.01-cache-2.11-cpan-d7a12ab2c7f )