How to use threading in Laravel to run stored procedures - php

I want to use php threads for asynchronously loading a function that executes a mysql stored procedure. The stored procedure takes a lot of time to load, so keeping it asynchronous is the only optimal solution, I found.
I have no idea on how to bring the threading inside Laravel. Laravel has queues but I want to do it directly in script with thread.

What i've done to approach a similar issue (I've done it in a sync command) is to create a class that extends from Thread and call it from the laravel code.
The class in your case might be something like this:
class LaravelWorker extends Thread
{
private $object;
public function __construct($object)
{
$this->object = $object;
}
public function run()
{
$object->runProcedure();
}
}
And you can call it at your code such as this:
$object = new ObjectWithProcedure();
$threadedMethod = new LaravelWorker($object);
$threadedMethod->start();
If, for some reason, you need to wait until the $threadedMethod finishes, you can do
$threadedMethod->join();
(more_code...)
And the more_code section will only execute once $threadedMethod has ended.
Hope it helps!

Related

How to process multiple task in codeigniter cli at the same time

I am not sure if this is doable or not. I am running cron job to process data and they are all independent of each other.
For example i have a data [x,y,z] and i have a method in the parent controller that does what it needs to do. Process takes little long and hence my queue is piling up since it is doing one at a time. I tried forking process but it loses connection to the mongo database. Therefore, I had to remove fork for now but please let me know if i can reconnect.
Pseudocode
MyTools.php
class MY_Tools extends CI_Controller {
...
public function process($item) {
Make curl request
Update database for the item
}
}
Tools.php
class Tools extends MY_Tools {
...
public function getAllDate() {
$data = fetchDataFromDB() => [X,Y,Z]
$i = 0
while ($i < sizeof($data) {
$this->process($data[$i]);
$i++;
}
}
}
if i can do this without waiting for another process to complete and just keep on going, that will be great
In addition, I am using php7
cimongo library for codeigniter and https://github.com/alcaeus/mongo-php-adapter
Possible Solution
For php7, i have used this for gearman installation
https://techearl.com/php/installing-gearman-module-for-php7-on-ubuntu
Codeigniter gearman library that I used : https://github.com/appleboy/CodeIgniter-Gearman-Library
To overcome static method accessing parent controller, use singleton method
I was struggling with this for a bit and hopefully it will help someone
Example
class MY_Tools extends CI_Controller {
private static $instance;
function __construct() {
parent::__construct();
self::$instance =& $this;
}
public static function get_instance()
{
return self::$instance;
}
}
To Access
MY_Tools::get_instance()->YOUR_PUBLIC_METHODS();
Hope this can help someone

Laravel / MVC: where to return partial response data

Edit: This question is more about how to create a contract within a function. How do I create methods that do simple things and have requirements between objects? Do I:
1) Add checks and exceptions in the start() method to create the contract and put the pausing loop in a different call? (Downside here is a minor repeat call to the data source.)
2) Add an event listener for whenever a timer is started to create the contract? (I'm not sure I can return data the way I would like with this method. I'm also not sure I can guarantee that the event will complete successfully before I start the new timer. May not matter that much in this case.)
3) Just return the ids from the start function and process them. (The function will be doing too much, but at least it will work properly with less overhead.)
========================================================================
I have this code in my model. This is a timer application and this code gets hit when starting a timer. Basically, any running timers should get paused and somehow the view needs to understand that it should refresh those timers.
public function start($input = array())
{
if($timers = TimeLog::where('status','running')->get()){
foreach($timers as $timer){
/** #var $timer TimeLog **/
$timer->pause();
}
}
$this->user_id = Auth::user()->id;
$this->addDetails($input);
$this->restarted_at = date('Y-n-d H:i:s'); //TODO timezones
$this->status = 'running';
$this->save();
}
I'm uncomfortable returning a list of paused timers from this function. Just doesn't seem to make sense.
I thought about moving the foreach to my controller, but this is really business logic and I wanted to make sure no running timers exist when I start a timer.
I could make another method in this class, which would solve the return issue, but then how do I guarantee that each start call will check for running timers?
This seems like a good fit for using the repository pattern as described here.
I recently had to solve a similar problem since I am just getting started with Laravel and I was putting all my business logic in either Model or Controller classes. I had business logic that didn't seem to make sense for either of those, and after some research I found Repositories.
I would try something like this:
class EloquentTimerRepository implements TimerRepository
{
/**
* Part of your TimerRepository interface
*/
public function startTimersForCurrentUser($inputs)
{
$this->pauseRunningTimers();
$newTimer = $this->createNewTimer($inputs);
$newTimer->start();
}
private function createNewTimer($inputs)
{
$timer = new Timer;
$timer->user_id = Auth::user()->id;
$timer->addDetails($input);
$timer->save();
return $timer;
}
private function getRunningTimers()
{
return TimeLog::where('status','running');
}
private function pauseRunningTimers()
{
if($this->getRunningTimers()){
foreach($timers as $timer){
/** #var $timer TimeLog **/
$timer->pause();
}
}
}
}
and then:
class Timer extends Model
{
public function start()
{
$this->restarted_at = date('Y-n-d H:i:s'); //TODO timezones
$this->status = 'running';
$this->save();
}
}
As for updating the view, you're going to have to either do a page reload or if you are using ajax, make a subsequent call to pull the latest timers and reset the page elements based on that data. There are probably ways to implement push (from the server) but I'm not familiar with those techniques yet.

PHP thread do not end

I tried to implement multithreading in php to fetch data from a data source parallely.
But in the process, the threads i create to fetch the data continue to remain in the memory, even after the fetching.
This is the class that i call
class ClassName extends Thread {
public function __construct($i){
$this->i=$i;
}
public function run(){
// functionCallToDataSource($this->i);
}
}
and i call this class here (in a loop).
$workers = new ClassName(parameter);
$workers->start();
$workers->kill(); //this isnt working
This kill() doesnt seem to work for me, as the memory is not reduced after the functions have been performed.
I have to restart my server to free the blocked memory

Chaining methods for adding items to a queue

I'm writing a log class which has several methods like info, error or warning to insert log entries into the database.
Until now every one of those methods directly made a db insert. This is not good performance whise when it comes to batch processing. I now want to solve this with creating a queue and only generate and fire one insert statement at the end of a task.
I'm now not sure if the following makes sense or is good practice. The way I would do it right now is chaining the methods to start and submit a queue like:
Log::queue()->info('Just somehting')->warning('Strange stuff')->submit();
Or if I wan't to directly insert it:
Log::info('Just something');
The class structure would for example look like this:
class Log {
protected $queue = array();
protected $isQueued = false;
public function queue() {
$this->isQueued = true;
return $this;
}
public function info() {
if($this->isQueued) {
//Add to queue
} else {
//Insert in db
}
return $this;
}
//All the other log types following...
public function submit() {
//Generate single insert statement from queue and insert it
}
}
I'm using a Laravel facade hence the static calls.
Is there anything wrong with this design? I'm not sure because for example Log::submit() for itself would make absolutely no sense but would be possible. Does it even matter?
What you should probably do is drop the queue/commit methods, instead take incoming logs and store them in an array on the object, and then you can use a callback like App::shutdown(function() {...}) to tell it to commit the in-memory log strings to the database once the application is done serving the request.
Also worth mentioning - If you're not restricted to using a SQL database, there are already several existing database Monolog handlers for Redis, Mongo and more. The underlying Monolog instance is available via Log::getMonolog().

Shared Resources Between PHP Children 'Threads'

I have a PHP script that spawns two child processes (pcntl_fork()) which each call methods of a single class instance (the names of the classes and methods and their functionality are simplified for easier explanation).
class Main_Class
{
public $array = array();
public function push($value) {
$this->array[] = $value;
}
public function pop() {
return array_shift($this->array);
}
}
$pc = new Thread_Creator();
$main_class = new Main_Class();
$pc->fork(array($main_class, 'push'), 1);
$pc->fork(array($main_class, 'pop'), 1);
The fork method is executed like so: call_user_func($main_class, 'pushToArray')
I intended these processes to share the same resources (one process pushes information into a public class variable of type array while one pops from it). Currently, both process run concurrently but only one seems to have access to the class variable $array.
Are shared resources possible between separate PIDs?
Any suggestions for solving this issue? (I would like to keep the processes separate as I intend to run them at different intervals)
If you need any more info or code snippets let me know
I was able to use shared memory to accomplish the task. For those interested, take a look here:
http://onlamp.com/pub/a/php/2004/05/13/shared_memory.html?page=2
http://www.php.net/manual/en/book.sem.php

Categories