I’m writing some plugins that do background batch processing, i.e. operations that take longer than 30 seconds. I’m creating objects with the necessary job parameters set like this (this is a hugely simplified example):
class MyPlugin_Create_Terms {
public $job_id;
public $terms;
public $taxonomy;
public $created = 0;
public function init( $terms, $taxonommy ) {
$this->job_id = uniqid();
$this->terms = $terms;
$this->taxonomy = $taxonomy;
return $this->job_id;
}
public function do_job( $object_storage ) {
foreach( $this->terms as $term ) {
wp_insert_term( $term, $this->taxonomy );
$this->created++;
$object_storage->save_object( $this->job_id, $this );
}
}
}
$create_terms = new MyPlugin_Create_Terms();
$job_id = $create_terms->init( $_POST['user_input_terms'], $_POST['user_input_taxonomy'] );
$object_storage = new MyPlugin_Object_Storage();
$object_storage->save_object( $job_id, $create_terms );
And in another process:
$object_storage = new MyPlugin_Object_Storage();
$create_terms = $object_storage->load_object( $job_id );
$create_terms->do_job( $object_storage );
While anywhere else:
$object_storage = new MyPlugin_Object_Storage();
$create_terms = $object_storage->load_object( $job_id );
echo "We have created {$create_terms->created} terms.";
Now the problem is implementing the Object_Storage
. I have figured out the following options for storing objects:
-
Transients. They apparently won’t do, since they have no guaranteed life-time (with caching, the transients might never be written to the database, I’ve learned).
-
Existing DB tables. Serialized PHP objects should not be saved to MySQL
text
fields, since they might containNULL
bytes (( I had a spectacular WSOD failure when serializing an object with aprotected
property to the usermeta table) :Note that this is a binary string which may include null bytes, and
needs to be stored and handled as such. For example, serialize()
output should generally be stored in a BLOB field in a database,
rather than a CHAR or TEXT field. – PHP Manual: serialize() -
Creating a custom table with
BLOB
type fields for serializing any object or alternatively, storing the object data without serializing. Feels like overkill. What are the best practices? -
Using the filesystem. Various factors like locking, atomic and non-atomic processes and file permissions complicate this. Specifically, since there will be two processes accessing the object concurrently, there is the problem with race conditions when they need to look at the same object.
-
Using _SESSION? Probably not good for two concurrent processes.
Any thoughts would be appreciated!
Store the object temporarily in the database, but implement
__sleep()
and__wakeup()
to avoid side effects.Alternatively, implement the
Serializable
interface and prepare the data in its methods. There is no need to store NULL values.Long term, you should consider that if you have a process which is going to regularly exceed the max execution time, then running it from inside an HTTP request and polling isn’t a great idea. Consider using the real cron system instead. Command line PHP processes don’t have a max execution time, normally, and can run until completion.
Short term, if you want to store it safely in a text field, like in a custom post type or meta or something, serialize it, then base64_encode the string. This will solve your problem with the null bytes. Just decode it and unserialize it when you need to retrieve it again.