Supplying context to UserAgent completion callback

36 views
Skip to first unread message

Jeremy Begg

unread,
Feb 28, 2017, 7:16:22 PM2/28/17
to Mojolicious
Hi,

I'm working on an application that uses Mojo::UserAgent to send data to another system, preferably non-blocking.
The code looks something like this (greatly simplified):

sub send_data {
   
my $data = shift;
   
my $ua = Mojo::UserAgent->new;
   
my $request = $ua->post($upload_url => $data) => sub {
                                 
my ($ua, $tx) = @_;
                                  post_process
($data);
                                 
});
   
return $request;
}


I am concerned that by the time the callback occurs, $data will contain something other than what was sent via the POST that sent it, and so the post-processing routine (not shown here) will misbehave.
The response body from the remote system does not contain any context information about the request sent to it; all it returns is a success/fail status and (if successful) the number of items uploaded.

How can I save the value of $data for use by the callback?  Is there a mechanism to attach local state information to the $ua->post() which is handed to the callback when it is invoked?
(I can't see any reference to such in the documentation for Mojo::UserAgent.)

Thanks,
Jeremy Begg

Dan Book

unread,
Feb 28, 2017, 8:38:08 PM2/28/17
to mojol...@googlegroups.com
By including $data in the callback, you are closing over it, thus preserving its value. However if $data is a reference, the data it references could change. If you copy the specific context information you need into lexically-scoped scalars beforehand, and close over those copies instead, you can avoid that possibility.

-Dan

--
You received this message because you are subscribed to the Google Groups "Mojolicious" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mojolicious+unsubscribe@googlegroups.com.
To post to this group, send email to mojol...@googlegroups.com.
Visit this group at https://groups.google.com/group/mojolicious.
For more options, visit https://groups.google.com/d/optout.

Jeremy Begg

unread,
Feb 28, 2017, 11:14:47 PM2/28/17
to Mojolicious
Hi,

I've realised that in my original problem statement (above) I omitted a critical line of code.
I've added that line below, i.e. my $res = $tx->result;

On Wednesday, March 1, 2017 at 10:46:22 AM UTC+10:30, Jeremy Begg wrote:
Hi,

I'm working on an application that uses Mojo::UserAgent to send data to another system, preferably non-blocking.
The code looks something like this (greatly simplified):

sub send_data {
   
my $data = shift;
   
my $ua = Mojo::UserAgent->new;
   
my $request = $ua->post($upload_url => $data) => sub {
                                 
my ($ua, $tx) = @_;

                                  my $res = $tx->result;
                                  post_process
($data);
                                 
});
   
return $request;
}

Jeremy Begg

unread,
Feb 28, 2017, 11:19:53 PM2/28/17
to Mojolicious
Given the better example, and Dan's suggestion, can you please clarify how the callback routine is processed?

I had thought it was not invoked until the HTTP transaction has completed, but now I'm thinking that it's invoked as soon as the HTTP request is sent and then the code stalls in $tx->result until the request completes.
Is that correct?  If so then I guess Dan's suggestion would be coded as:

sub send_data {
   
my $data = shift;
   
my $ua = Mojo::UserAgent->new;
   
my $request = $ua->post($upload_url => $data) => sub {
                                 
my ($ua, $tx) = @_;

                                  my $localdata = $data;
                                  my $res = $tx->result;  
# stall here until HTTP response is received
                                  post_process
($localdata);
                                 
});
   
return $request;
}

Dan Book

unread,
Feb 28, 2017, 11:33:41 PM2/28/17
to mojol...@googlegroups.com
No, that would be a blocking request. The non-blocking format creates and sends the request, and stores the passed coderef to be called once the response is received. Additionally, making a shallow copy of the reference doesn't achieve anything, I meant (if it is a reference) you would need to copy the individual data within that you wish to use, outside of the coderef.
-Dan

--

Jeremy Begg

unread,
Mar 1, 2017, 2:14:43 AM3/1/17
to Mojolicious
Hi,

I've just re-read the section on Closures in "Programming Perl" and now I think I understand how this works, at least more so than I did earlier.

Thanks!
Reply all
Reply to author
Forward
0 new messages