Comments (9)
Amp is great for this but it is non-trivial to integrate into conventional PHP applications. Since you mentioned AJAX I am assuming you have conventional PHP deployment where each PHP process handles a single web request. In this typical execution context, you have a PHP script that is executed in it's entirety for a single HTTP request, usually returning an HTTP response, and exiting.
Amp is an event loop that will run until there is nothing else to run on the loop. So once you start an Amp event loop, it blocks until completion, and provides an API for you to run tasks on the event loop. If you re-create your example with a single PHP script and run it from the command line, you will see the exact same behavior: your command line script runs synchronously for 30 seconds and exits. The event loop has one task to run after a delay of 30 seconds, and exits after all tasks complete. The asynchronous power of Amp comes when you use it to run your entire application, allowing any task (including handling HTTP requests/responses) to be run on the event loop. This lets you do things like immediately return a response to the client, and simultaneously kick off a long-running job on the event loop.
Now with your existing application, you have a couple options.
- Since you're already using a message-broker (ZMQ), that is an ideal solution for handling async/long-running jobs in conventional PHP applications. You can use ZMQ to communicate between your current application, and an Amp event loop to run jobs.
- You can also just use
shell_exec
to kick off background process as well right after the upload completes. Likeshell_exec("poll_api.php &")
- You can skip Amp for now and create a PHP script that polls for jobs from ZMQ, looking for messages to run that job (see https://github.com/zeromq/php-zmq/blob/master/examples/simple-server.php).
from amp.
Thanks for your suggestions, they're very helpful. I was actually just thinking of doing your first suggestion but I might be missing something.
For contextual purposes, I have a CLI-ran PHP Ratchet script with websockets. This is where I send my ZMQ requests to as well. It also tracks clients logging on and off the site so it is an infinitely running PHP React Event Loop (server). I thought that if I ran the exact same example (I posted earlier) within the CLI-ran PHP Ratchet's onMessageReceived()
function, that I'd be able to execute the task asynchronously. But I must be missing something because the code I had put after the async
task only executed 30 seconds later. Am I missing an amp event loop that I need to instantiate myself on another CLI-ran PHP script for the example I copied from the docs to work? If so, is it possible to somehow get this async
task to use my PHP Ratchet's (React) event loop somehow haha?
As for your 2nd suggestion, I did actually try that at first and got it to work (although with exec
as opposed to shell_exec
) exactly how I wanted it to, but I had 2 main concerns with it, specifically:
- Passing arrays/objects as parameters to the script.
- What happens when a 2nd client uploads a video at the same time (i.e. would 2 background processes run simultaneously and if so how many simultaneous background processes can the system handle and what happens when it can't OR would they be scheduled to run sequentially).
from amp.
Hey @fuad-tareq, thank you for the detailed summary of your current situation. It really helps giving you the right hints.
As @bennnjamin already mentioned, thing are only async / non-blocking within the event loop. If you're already running Ratchet, that's great! Ratchet makes use of ReactPHP, which is another event loop implementation in PHP. However, we've got you covered with https://github.com/amphp/react-adapter. It let's you run any Amp / ReactPHP application in combination on a single event loop. Without the adapter, each event loop would block the other from executing. Given that, I'd probably move polling into the Ratchet process.
from amp.
In that case you definitely have the right setup for what you're trying to achieve. This line $result = Amp\Promise\wait($promise);
will cause your application to block until the promise resolves so if your server has this code exactly as written, any code after that line will be executed 30 seconds later. Instead, you want to use
$promise->onResolve(function ($exception, $value) {
//handle $exception, or $value here
});
which is a callback that will be ran after your promise completes, so 30 seconds later in your case. This will not block the event loop.
exec
/shell_exec
is not the most scalable solution for the reasons you mentioned. Since you already have a separate PHP process running an event loop, I would not recommend it. Amp or React is a far superior solution. To answer the question though 1) Passing data to the script is done by serializing it, typically with json_encode
and json_decode
2) yes you would get two background processes and it may not be scalable depending on your client load. There are more robust solutions to allow X number of jobs to run simultaneously, etc.
from amp.
Ah, I must be doing something really silly now because I did exactly as you suggested @bennnjamin but it only partially worked. I have this exact snippet in my onMessageReceived()
handler in the React event loop:
function asyncMultiply($x, $y) {
// Create a new promisor
$deferred = new \Amp\Deferred;
// Resolve the async result 30s from now.
Loop::delay($msDelay = 30000, function () use ($deferred, $x, $y) {
$deferred->resolve($x * $y);
});
return $deferred->promise();
}
if ($data['w_async'] === 'true') {
error_log('async start');
$promise = asyncMultiply(6, 7);
$promise->onResolve(function ($exception, $value) {
error_log('onComp: ' . print_r($exception, true));
error_log('onComp: ' . print_r($value, true));
});
error_log('async end');
}
And I'm getting the following output immediately on execution in my error_log:
async start
async end
What I expected:
async start
async end
... 30 seconds later ...
onComp ...
onComp ...
So while it is no longer blocking my event loop, I am not getting the onComp
error_logs (inside the onResolve
) I expect 30 seconds later. What am I missing?
PS: @kelunik's brilliant answer went straight over my head, not sure if he means that there's a more efficient way to achieve what I am intending using amphp's React adapter... or perhaps I'm supposed to combine his answer with yours in order to get the promise to work as intended?
from amp.
You do need to ensure you are using amphp/react-adapter as @kelunik mentioned. This is because your application can only have one event loop running. Both Amp and React provide their own event loop implementations. The adapter allows you to mix both Amp and React libraries in the same application, which is great!
You could also try just getting the example to work with React's own Promise library (https://github.com/reactphp/promise) since it seems you already have an event loop running under React.
from amp.
Thanks for the quick response. Upon looking more into this, I am a bit confused because it seems there's React PHP (as referenced by you which is on v1.3 right now) and there's react/zmq which is what I have installed and it's on version 0.4. I suspect those are 2 different libraries... Would your react-adapter still work with this setup?
from amp.
I'm not familiar with React's versioning semantics so you may need to open an issue with them. react-adapter allows you to run any React PHP library the expects a LoopInterface
on the Amp event loop. If you are using React, it might be simpler to stick with only react libraries for now (dropping any Amp libs), or create a simple project that uses react-adapter to run React libraries on the Amp event loop.
from amp.
Thanks for all your help with this. It took forever and a half and I had to manually update the ReactPHP part of the react/zmq library. But I finally managed to get it working with ReactPHP's Promises as you suggested. I did like amphp more but since ReactPHP was already part of my Ratchet PHP server, it made sense to use the latter.
from amp.
Related Issues (20)
- Improve UnhandledFutureError message with class name
- Thoughts on v3 HOT 13
- Promise timeout with loop defer function HOT 3
- QUIC support HOT 2
- A concise way of resolving results that may turn out to be Promise, Generator or something else HOT 4
- An object reference sticks in the library HOT 1
- stream_select hangs forever when FDs > 1024 are used HOT 5
- Getting access to child process data on SIGCHLD in Loop::onSignal. HOT 16
- Confusing diagram in README HOT 6
- Return self in Future::ignore HOT 1
- UnhandledFutureError is hard to debug HOT 2
- Migration guide for combinator functions HOT 5
- FiberError: Cannot switch fibers in current execution context on Laravel HOT 4
- 32 bit PHP: Return value of Amp\Loop\NativeDriver::now() must be of the type int, float returned HOT 5
- Functions should require callable instead of closures HOT 10
- Any way to create or get a context for coroutine. HOT 5
- Version confusion HOT 8
- Shouldn't Future::finally() pass the future data to the provided callback? HOT 7
- Event loop terminated without resuming the current suspension (the cause is either a fiber deadlock, or an incorrectly unreferenced/canceled watcher) HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from amp.