How to Build and Run Custom ThinkPHP Console Commands with Redis Integration
This guide walks you through creating a custom ThinkPHP console command, configuring it in the application, executing it via the CLI, handling logs, running it as a background daemon with nohup, and extending it to subscribe to Redis key‑event notifications.
Creating a Custom ThinkPHP Command
From the project root generate a new command class named TestJobs with the ThinkPHP command generator:
cd tp5
php think make:command TestJobsThe generator creates app\command\TestJobs.php containing a skeleton class that extends think\console\Command.
Implementing the Command
Replace the generated skeleton with a meaningful name, description and a required argument type:
namespace app\command;
use think\console\Command;
use think\console\Input;
use think\console\Output;
use think\facade\Log;
class TestJobs extends Command
{
protected function configure()
{
$this->setName('hello')
->setDescription('Test command: hello:add | hello:edit')
->addArgument('type', Command::ARG_REQUIRED, 'type of test job');
}
protected function execute(Input $input, Output $output)
{
$type = $input->getArgument('type');
if ($type === 'hello:add') {
$this->helloAdd();
} elseif ($type === 'hello:edit') {
$this->helloEdit();
}
}
private function helloAdd()
{
Log::error('Custom command executed: ' . __METHOD__);
}
private function helloEdit()
{
Log::error('Custom command executed: ' . __METHOD__);
}
}Registering the Command
Create (or edit) application/command.php and return the command class:
return [
\app\command\TestJobs::class,
];Running and Verifying the Command
List all available commands: php think You should see an entry similar to: hello Test command: hello:add | hello:edit Execute a specific sub‑command: php think hello hello:add Check the application log (usually runtime/log) – an error‑level entry containing the method name confirms execution.
Running the Command as a Daemon
For long‑running or blocking tasks (e.g., a Redis pub/sub listener) start the command with nohup so it survives terminal closure:
nohup /usr/local/php/bin/php /var/www/tp5/think hello hello:edit > /dev/null 2> /dev/null &Extending the Command for Redis Key‑Event Subscription
Define a new command class Jobs that accepts the argument redis-notify-key-events and triggers a Redis subscription helper:
namespace app\command;
use think\console\Command;
use think\console\Input;
use think\console\Output;
use app\service\RedisSubscribe;
class Jobs extends Command
{
protected function configure()
{
$this->setName('jobs')
->setDescription('order_count|redis-notify-key-events|transaction_account_tables')
->addArgument('type', Command::ARG_REQUIRED, 'type of job');
}
protected function execute(Input $input, Output $output)
{
$type = $input->getArgument('type');
if ($type === 'redis-notify-key-events') {
$this->notifyKeySpaceEvents();
}
}
private function notifyKeySpaceEvents()
{
$service = new RedisSubscribe();
$service->subscribe();
}
}RedisSubscribe Service
The service creates a Redis client, disables the read timeout, and subscribes to the pattern __keyevent@1__:expired. When a key‑space expiration event is received, the key is parsed and can be used for business logic (e.g., order cancellation).
namespace app\service;
use think\facade\Log;
use app\common\BaseRedis;
class RedisSubscribe
{
public function subscribe()
{
$redis = BaseRedis::plocal();
// Prevent the client from timing out while waiting for events
$redis->setOption(\Redis::OPT_READ_TIMEOUT, -1);
$redis->psubscribe(['__keyevent@1__:expired'], function ($redis, $pattern, $channel, $msg) {
Log::info('[Subscribe] Expired key: ' . $msg);
// Expected key format: S{order_id}:{event_code}
$parts = explode(':', $msg);
$eventKey = $parts[1] ?? '0'; // e.g., S20190722100001
$eventStatus = $parts[0] ?? '0'; // e.g., 1001
// TODO: implement business handling based on $eventKey and $eventStatus
});
}
}Run the subscription command as a daemon:
nohup /usr/local/php/bin/php /var/www/tp5/think jobs redis-notify-key-events > /dev/null 2> /dev/null &Redis Key Naming Convention
Keys used for order‑related events follow the pattern S{order_id}:{event_code}: S20190722100001:1001 – 1001 denotes an order‑expiration event (e.g., QR code expired). S20190722100001:1002 – 1002 could represent a 30‑minute unpaid‑order cancellation.
When the Redis key expires, the subscribed command receives the full key string in $msg, parses the order identifier and event code, and can execute the appropriate business logic (such as marking the order as cancelled).
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Open Source Tech Hub
Sharing cutting-edge internet technologies and practical AI resources.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
