When I queue up a laravel mailable to execute 15 minutes later like so:
Mail::to($user)->later(now()->addMinutes(15), new EmailConfirm($user));
Laravel will store the EmailConfrim class in the payload column in the jobs table.
If I do a release which changes the class name EmailConfirm to ConfirmEmail I will get the following error when the code executes 15 minutes later:
prod.ERROR: Illuminate\Mail\SendQueuedMailable::handle(): The script
tried to execute a method or access a property of an incomplete object.
Please ensure that the class definition
"App\Mail\Mailables\EmailConfrim" of the object you are trying to
operate on was loaded _before_ unserialize() gets called or provide an
autoloader to load the class definition
This error is telling me that the class defined in the payload no longer exists.
A solution I've been toying with is to add an app_version_number to the laravel generated jobs table. I would then not let my laravel workers die until all the jobs are executed for that version before running:
php artisan queue:restart.
This will take me a bit of time to reliably code this as it will be specific to our prod environment. How could I go about managing this problem in a more eloquent way?
I'd temporarily leave both classes in the codebase, deploy that, and then 15 minutes (or whatever the maximum amount of time a job lingers around) later push the removal of the old one.
This answer is very similar to https://stackoverflow.com/a/54314953/2191572 BUT I would recommend maintaining the EmailConfirm via extension to avoid double-duty maintenance while your queue catches up:
class EmailConfirm extends ConfirmEmail
{
// This is just a shell/alias/wrapper/whatever for the real class
}
class ConfirmEmail
{
function __construct( $param )
{
// Maintain this class
}
}
15 minutes isn't so bad in terms of wait time but what if your queue doesn't catch up for several days and you need to change ConfirmEmail multiple times?
Related
<?php
namespace Test;
class A {
public function T(){
sleep(1000);
//Code not possible for thread to perform
}
}
?>
But, When call method T, Program Stucking occured.
how can i delay without stucking?
i can use thread but, the code that I wrote with using API doesn't accept Thread.
sorry for bad English, and thanks
You have to create a new \pocketmine\Thread object for long running task, as mentioned in the documentation of the AsyncTask class:
[...]
* An AsyncTask does not have its own thread. It is queued into an AsyncPool and executed if there is an async worker
* with no AsyncTask running. Therefore, an AsyncTask SHOULD NOT execute for more than a few seconds. For tasks that
* run for a long time or infinitely, start another {#link \pocketmine\Thread} instead.
[...]
So it looks like the API support threads, so use them.
I have made a library that explicitly allows you to use a sleep-alike syntax based on tasks, using PHP generators: https://github.com/SOF3/pmutil/blob/master/src/sofe/pmutil/SleepyTask.php
Example use: https://gist.github.com/SOF3/36813c09f086de7307dd9dab908f4aa4
Note that the code targets a really old API (3.0.0-ALPHA10), so you have to update it before using.
I'm currently trying to retrieve the SMTP Queue-ID when using the Laravel (5.6) Mail class.
I have copied the file vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php to /app/OverriddenAbstractSmtpTransport.php and made an alias in config/app.php, made my changes:
1:
on line#395 I added return in front of the line, so we obtain the output
2:
line#492 replaced with $message->queue_ids[] = $this->streamMessage($message);
So I can access queue_ids from the message property in the Illuminate\Mail\Events\MessageSent-event
Now this works, but I don't think it's a very safe approach to modifying the vendor class, as it might cause a breaking change when running security updates.
Is there a simpler/better/safer solution to this ?
Copying the whole class is risky - if any updates are done to the vendor class in a newer version, they'll never make it into your copy. A safer way is to extend the original class and overwrite those 2 functions. There is still a risk of some changes being done to those functions in vendor class, but it's much lower now. Another option would be to extend the original class and add new methods - they will have access to all public and protected properties/methods of the original class and that could be enough to get you what you need.
Whatever version you choose, you'll need to later register the new class as a new driver/transport for Swift. Check the following snippet for an example: https://gist.github.com/maxwellimpact/46ded5c553f68946d13d
I'm working in PHP 4 with classes but there's not __autoload function, so I have problems to load my classes because they are intertwined.
I have a class Ship and a class Movement. The class Ship contains an Movement object and the class Movement contains an Ship object.
So when I do the require Ship, the class is read and throws error when reach the new Movement and conversely.
Some solution? ;)
PHP 4 is really, really old and not-supported. The best option is to move to PHP 5.
If you can't, create a bootstrap file, which requires all class definitions (in the correct order in case of inheritance); make sure the class definition files contains only class definition (and not executable code like $obj = new Movement) and require this file in each file you are actually running in your application.
The point is, the class definition of Movement is not needed before the new Movement statement, and if this statement is in some Ship's method (even if it's in the constructor), you can safely load the Ship.php, then Movement.php, then run the code and it will work.
Also, make sure to load all class definitions before starting the session, if you are using sessions and serialize objects in it.
I am trying to use php-resque to queue and execute ffmpeg conversions on my server. I understand broadly how it should work, but I am having some trouble with the details and can not find any tutorials. Specifically, I don't understand where I should place my job classes, and how to give the classes to my workers and start my workers. The read me only says "Getting your application underway also includes telling the worker your job classes, by means of either an autoloader or including them."
Hopefully someone can outline the overall structure of using php-resque.
You can put your job classes where you want. It'll depend on your application structure.
How to create a job class
For example, let's suppose the class VideoConversion, used for the ffmpeg conversion.
class VideoConversion {
public function perform() {
// The code for video conversion here
}
}
In your main application, before using php-resque, let's say you have something like that
public function uploadVideo() {
// Upload and move the video to a temp folder
// Convert the video
}
And you want to enqueue the 'convert video' part. Let's just queue it to the convert queue:
public function uploadVideo() {
// Upload and move the video to a temp folder
// Let's suppose you need to convert a 'source video' to a 'destination video'
Resque::enqueue('convert', 'VideoConversion', array('origine-video.avi', 'destination-video.avi'));
}
When queuing the job, we passed the path to the source and destination video to the VideoConversion class. You can pass other argument, it'll depend on how your VideoConversion class is written.
A worker will then poll the convert queue, and execute the VideoConversion job. What the worker will do is to instantiate the VideoConversion class, and execute the perform() method.
The job arguments (array('origine-video.avi', 'destination-video.avi')), third argument when queueing the job with Resque::enqueue, will be available inside the perform() method via $this->args.
# VideoConversion.php
class VideoConversion
{
public function perform() {
// $this->args == array('origine-video.avi', 'destination-video.avi');
// Convert the video
}
Find your job classes
The VideoConversion class can be put anywhere, but you have to tell your workers where to find it.
There's multiple ways to do that
Put you jobs classes in the include_path
In your .htaccess or the apache config, add the directory containing all your job classes to the include path. Your workers will automatically find them.
Main issue with this method is that all your jobs classes must be in the same folder, and that all your job classes are available everywhere.
Tell each worker where to find your job classes
When starting the worker, use the APP_INCLUDE argument to point to the job classes 'autoloader'.
APP_INCLUDE=/path/to/autoloader.php QUEUE=convert php resque.php
The above command will start a new worker, polling the queue named convert.
We're also passing the file /path/to/autoloader.php to the worker. (see here to learn to start a worker)
Technically, the worker will include that file with include '/path/to/autoloader.php';.
You can then tell the workers how to find your job classes:
Use basic include
In the '/path/to/autoloader.php':
include /path/to/VideoConversion.php
include /path/to/anotherClass.php
...
Use an autoloader
Use php autoloader to load your job classes.
Use set_include_path()
set_include_path('path/to/job');
That way, your jobs are in the include_path just for this worker.
Closing thought
APP_INCLUDE is binded to the worker you're starting. If you're starting another worker, use APP_INCLUDE again. You can use a different file for each worker.
You can also design your job classes to execute more than one job. There's a tutorial explaining how to do that. It covers from the basic of a queue system to how to use and implement it.
If it's still not enough, take a look at resque documentation. php-resque API is exactly the same. Only difference is that Resque job classes are written in Ruby, whereas php-resque's one are in php.
Hi Please check out following tutorial on how to use resque with phalcon.
http://www.mehuldoshi.in/background-jobs-phalcon-resque/
It's really irking me that PHP considers the failure to instantiate an object a Fatal Error (which can't be caught) for the application as a whole. I have set of classes that aren't strictly necessary for my application to function--they're really a convenience. I have a factory object that attempts to instantiate the class variant that's indicated in a config file.
This mechanism is being deployed for message storage and will support multiple store types:
DatabaseMessageStore
FileMessageStore
MemcachedMessageStore
etc.
A MessageStoreFactory class will read the application's preference from a config file, instantiate and return an instance of the appropriate class.
It might be easy enough to slap a conditional around the instantiation to ensure that class_exists(), but MemcachedMessageStore extends PHP's Memcached class. As a result, the class_exists() test will succeed--though instantiation will fail--if the memcached bindings for PHP aren't installed.
Is there any other way to test whether a class can be instantiated properly? If it can't, all I need to do is tell the user which features won't be available to them, but let them continue one with the application.
If you use autoloading to load your class files (which you should), you can throw a custom Exception right at the end of your autoloader function(s) if the requested class in still not available for instantiation.
This should trigger any time a non existing class is being used, even for PHPs internal classes. So it should trigger in your case.
If your problem is to catch your Fatal Error you should try to write your own error handler and act accordingly to the error message.
This way you can workaround you heritage problem with Memcache.
As far as I can tell, this can't be done short of PHP 5.3. What I did instead was to make the factory class check for the existence of Memcached before instantiating the class that extends it. It's clumsy and far too brittle for my tastes, but it's working for now. When we upgrade to 5.3, I'll rework it a bit.