I have a laravel project with codebird-php lib there. And I trying to set a cron job to start scheduling my streaming commands. On my local machine with Ubuntu 16 it works perfectly, every minute creating a stream to twitter and on 55 second it dies.
But on the remoted VPS it not scheduled my command. I've tried it by cron, by tiping in terminal and have no efeect. Can anyone explain me where I've got a stupid mistake and what difference have in cron work Ubuntu 15.04 and Ubuntu 16.04?
Here is the code of commands:
connect command setting streams and start them
class ConnectToStreamingAPI extends Command
{
protected $signature = 'connect';
protected $run = [];
protected $users;
protected $description = 'Connect to the Twitter Streaming API to search tweets by keywords';
protected $twitterStream;
public function __construct(User $user)
{
$this->users = $user::where('id', '>', '1')->pluck('id')->toArray();
parent::__construct();
}
public function handle()
{
//set_time_limit(59);
$this->setRun();
$this->runUserStreamCommand();
return "Fired";
}
protected function setRun()
{
foreach ($this->users as $user) {
$this->addToRun($user);
}
}
protected function runUserStreamCommand()
{
foreach ($this->run as $process) {
$process->setPty(true);
$process->start();
}
$count = count($this->run);
while (count($this->run) > 0) {
foreach ($this->run as $key => $process) {
$childProcess = $process->getPid() + $count;
try {
$process->checkTimeout();
} catch (ProcessTimedOutException $e) {
exec("kill -15 " . $childProcess);
}
if (!$process->isRunning()) {
unset($this->run[$key]);
}
}
}
}
protected function addToRun($user_id)
{
$this->run[] = new Process("php /path/to/artisan stream $user_id", null, null, null, 50);
}
}
And here is Stream command
class StreamingCommands extends Command
{
protected $signature = 'stream {id}';
protected $description = 'create stream to twitter for one user';
public function __construct()
{
parent::__construct();
}
public function handle()
{
$id = $this->argument('id');
$user = User::find($id);
Codebird::setConsumerKey($user->consumer_key, $user->consumer_secret);
$stream = new TwitterStream();
$stream->setToken($user->twitterData->token, $user->twitterData->token_secret);
$keywordArray = array();
$ids = array();
foreach ($user->campaigns as $campaign) {
$ids[] = $campaign->id;
$keywordArray = array_merge($keywordArray, Keyword::whereCampaignId($campaign->id)->pluck('keyword')->toArray());
}
$keywords = Keyword::whereIn('campaign_id', $ids)->where('rejected', 0)->get();
$stream->setKeywords($keywords);
$stream->setStreamingCallback('processTweet');
$keywords = implode(',', $keywordArray);
$this->info("start stream to user $id");
$stream->statuses_filter('track=' . $keywords);
}
}
And cron job
* * * * * php /path/to/artisan schedule:run >> /dev/null 2>&1
And schedule is just a
$schedule->command('connect')->everyMinute();
As for the comments and the changes, you clearly have two different systems 16 and 15, with different software and dependencies installed. Unfortunately, there's no simple way of fixing this kind of glitch, you have to check everything, it can still be a not listed PHP dependency or even an operating system dependency and/or user acces rights (you are starting and killing processes, is it working or abending?), but your app is working fine in 16, so you can probably forget about Laravel and Composer and focus on PHP and the OS layers.
The thing is, from here, without acces to your server, it's very hard to guess, so sorry if it doesn't help much.
Related
I have multiple supervisor in horizon, and they work normally, the problem is that I want to interact with them by my own web interface, and by interacting I mean pause them and continue (unpause them).
To do that I want to be able as much as possible, without using system (in artisan horizon:pause-supervisor it sends posix_kill($supervisor->pid, 12)).
I tried to instantiate the supervisor by doing this :
class HorizonManager
{
private SupervisorRepository $supervisors;
private MasterSupervisorRepository $masters;
private WorkloadRepository $workload;
private RedisJobRepository $jobRepository;
private QueueManager $queueManager;
public function __construct(MasterSupervisorRepository $masters, SupervisorRepository $supervisors, WorkloadRepository $workload, RedisJobRepository $jobRepository, QueueManager $manager)
{
$this->masters = $masters;
$this->supervisors = $supervisors;
$this->workload = $workload;
$this->jobRepository = $jobRepository;
$this->queueManager = $manager;
}
public function pauseSupervisor(string $supervisorName){
$supervisor = $this->supervisors->find($supervisorName);
$supervisorOpt = new SupervisorOptions(...$supervisor->options);
$sup = new Supervisor($supervisorOpt);
$sup->pause();
$sup->persist();
return $this->supervisors->find($supervisorName);
}
}
In the return from the function, I have the supervisor paused, but it's not really paused (even If I persist the instantiate supervisor it's still running as a process)
For those interested I failed doing it by instanciating it so instead I send the command using artisan call :
define('SIGUSR2', 12);
Artisan::call('horizon:pause-supervisor', ['name'=>$supervisorName]);
$supervisor = $this->supervisors->find($supervisorName);
$supervisor->status = 'paused';
I want to add cron job dynamically once user install a php application on their server, like admin configuration, I need to set cron job dynamically once going thought its configuration settings in php?
I am using codeigniter to set the cron job, also I added the same from cpanel manually and it is working fine.
You can create a file in
/etc/cron.d
and use PHP's file_put_contents() to update the file. However, you'll need to elevate PHP or Apache's permissions (depending on your PHP handler). This isn't recommended since it leads to security issues.
If you're using Cron to run PHP scripts, then you can call the scripts directly using PHP every X amount of time. Create a variable in your database representing the last time your script was run. If X amount of time passed since the script was run, then you run the script and update the variable.
If the script takes a long time to execute, then use PHP to run it in a separate process, so the user doesn't have to wait for it to finish.
Thanks
First You have to create one txt file for example crontab.txt
then you have to use shell script like below
exec ( 'sudo crontab -u apache -r' );
file_put_contents ( '/var/www/html/YOUR_PROJECT/crontab.txt',"25 15 * * * php /var/www/html/YOUR_PROJECT/YOUR_CONTROLLER/YOUR_METHOD'.PHP_EOL);
And Lastly, you have to execute that file like
exec ( 'crontab /var/www/html/YOUR_PROJECT/crontab.txt' );
Hope this will help you.
you can do this using shell script
shell_exec('echo "25 15 * * * <path to php> /var/www/cronjob/helloworld.php > /var/www/cronjob/cron.log" | crontab -')
you can use these functions or class
class Crontab {
// In this class, array instead of string would be the standard input / output format.
// Legacy way to add a job:
// $output = shell_exec('(crontab -l; echo "'.$job.'") | crontab -');
static private function stringToArray($jobs = '') {
$array = explode("\r\n", trim($jobs)); // trim() gets rid of the last \r\n
foreach ($array as $key => $item) {
if ($item == '') {
unset($array[$key]);
}
}
return $array;
}
static private function arrayToString($jobs = array()) {
$string = implode("\r\n", $jobs);
return $string;
}
static public function getJobs() {
$output = shell_exec('crontab -l');
return self::stringToArray($output);
}
static public function saveJobs($jobs = array()) {
$output = shell_exec('echo "'.self::arrayToString($jobs).'" | crontab -');
return $output;
}
static public function doesJobExist($job = '') {
$jobs = self::getJobs();
if (in_array($job, $jobs)) {
return true;
} else {
return false;
}
}
static public function addJob($job = '') {
if (self::doesJobExist($job)) {
return false;
} else {
$jobs = self::getJobs();
$jobs[] = $job;
return self::saveJobs($jobs);
}
}
static public function removeJob($job = '') {
if (self::doesJobExist($job)) {
$jobs = self::getJobs();
unset($jobs[array_search($job, $jobs)]);
return self::saveJobs($jobs);
} else {
return false;
}
}
}
Hi thank you for the replies, i got my answers now, based on the replies
I tried to add a new cron job to crontab file using php (codeigniter):
following is my answer
$phppath = exec('which php');
$user_file_path = getcwd();
$cronjob1 = "0 0 1 * * $phppath $user_file_path/index.php
automatic_updates/leave_update_cron";
// run each cron job
// get all current cron jobs
$output = shell_exec('crontab -l');
// add our new job
file_put_contents('/tmp/crontab.txt', $output.$cronjob1.PHP_EOL);
// once append the job, execute the new file
exec('crontab /tmp/crontab.txt');
This will add a new cron job without deleting anything on the current cron job file
I have a hosting platform that at midnight resets all cronjob added on there system to 15 from what ever they where set to. Our plan is to set up a script that run's every 8hrs and resets these back, so the process they manage are minimally interrupted. It is shared hosting, but hosting companies solution it an upgrade and a massive rise in costs.
The server specs are cPanel Version - 70.0 (build 69) | Apache Version - 2.4.39 |PHP Version - 7.2.18 |MySQL Version - 10.2.24-MariaDB-cll-lve |Architecture - x86_64 | Operating System - linux
We have been suggested using a PHP class called Crontab to achieve this.
When we add a job, it appears in our cron job section of our server, but if we try to delete it from the server we get the following error 'Error New Lines are not permitted in crontab entries'. How ever we can remove the job via the Crontab class.
<?php
class Crontab {
static private function stringToArray($jobs = '') {
$array = explode("\r\n", trim($jobs)); // trim() gets rid of the last \r\n
foreach ($array as $key => $item) {
if ($item == '') {
unset($array[$key]);
}
}
return $array;
}
static private function arrayToString($jobs = array()) {
$string = implode("\r\n", $jobs);
return $string;
}
static public function getJobs() {
$output = shell_exec('crontab -l');
return self::stringToArray($output);
}
static public function saveJobs($jobs = array()) {
$output = shell_exec('echo "'.self::arrayToString($jobs).'" | crontab -');
return $output;
}
static public function doesJobExist($job = '') {
$jobs = self::getJobs();
if (in_array($job, $jobs)) {return true;} else {return false;}
}
static public function addJob($job = '') {
if (self::doesJobExist($job)) {
return false;
} else {
$jobs = self::getJobs();
$jobs[] = $job;
return self::saveJobs($jobs);
}
}
static public function removeJob($job = '') {
if (self::doesJobExist($job)) {
$jobs = self::getJobs();
unset($jobs[array_search($job, $jobs)]);
return self::saveJobs($jobs);
} else {
return false;
}
}
}
//$output = shell_exec('crontab -l'); //Check server output
//echo nl2br($output); //Make it readable
Crontab::addJob('*/15 * * * * /opt/alt/php56/usr/bin/php -q /home/path/bob.php process-log >/dev/null 2>&1');
Crontab::removeJob('*/15 * * * * /opt/alt/php56/usr/bin/php -q /home/path/bob.php process-log >/dev/null 2>&1');
?>
The reason this is a concern is that for there to be a server error, then code inputting the cronjob must not be doing it right, I have hear of issue when running similar processes on windows servers, but the php file running the code is in the root of the linux server, so wasn't expecting to have issues.
IF someone could explain why this error is occurring and how to fix it, that would be greatly appreciated, let me know if you need any more info.
Cheers in advance.
I am using Symfony 3 framework with pheanstalk php library. I run the app on server with Linux Debian Jesse. The job creation works ok and if run the worker from terminal it works like it should. But when I added the command to crontab I see that the command do not work. There is not any log in /var/main/user to help me with debuging. I will be very glad for any help.
This is my worker command (only the execute function):
protected function execute(InputInterface $input, OutputInterface $output)
{
$output->writeln("\n<info>Beanstalk worker service started</info>");
$tubes = $this->getContainer()->get('app.job_manager.power_plant')->getTubes();
if ($input->getOption('one-check')) {
// run once
foreach ($tubes as $tubeName) {
if ($tubeName != "default") {
$this->getContainer()->get('app.queue_manager')->fetchQueue($tubeName);
}
}
$output->writeln("\n<info>Beanstalk worker completed check and stoped</info>");
} else {
// run forever
set_time_limit(0);
max_execution_time(0);
while (1) {
foreach ($tubes as $tubeName) {
if ($tubeName != "default") {
$this->getContainer()->get('app.queue_manager')->fetchQueue($tubeName);
}
}
}
$output->writeln("\n<info>Beanstalk worker stoped</info>");
}
}
This is my app.queue_manager function to get job from queue and run command:
public function fetchQueue($tubeName)
{
if ($this->pheanstalk->getConnection()->isServiceListening()) {
while (true === is_object($job = $this->pheanstalk->watch($tubeName)->ignore('default')->reserve(self::WATCH_TIMEOUT))) {
$data = json_decode($job->getData(), true);
$this->worker($data);
$this->pheanstalk->delete($job);
}
}
}
And the worker to run command
public function worker($data)
{
$application = new Application($this->kernel);
$application->setAutoExit(false);
$parameters = [];
$parameters['command'] = $data['command'];
foreach ($data['meta'] as $key => $param) {
$parameters[$key] = $param;
}
$input = new ArrayInput($parameters);
$output = new NullOutput();
return $application->run($input, $output);
}
This is my crontab that do not work:
#reboot /usr/bin/php /var/www/mose-base/bin/console beanstalk:worker:start
I created another cron tab that works ok. It works every 15 min, and the difference is that do not have infinite loop (while(1)) so it goes only once thru tubes and than finished. But it is not what i want. I want infinite loop that works all the time like I created it with first crontab:
*/15 * * * * /usr/bin/php /var/www/mose-base/bin/console beanstalk:worker:start --one-check
If it works in the console, it doesn't work for your file user permissions. Check it.
You can report your error by email with this job
*/15 * * * * /usr/bin/php /var/www/mose-base/bin/console beanstalk:worker:start --one-check 2>&1 | mail -s "mysql_dump" example#mail.example
I used rc.local. It solve the problem. Tnx FreudianSlip
I'm curios if Zend has a component which can make use of the shell. For example I want to do an shell command like this:
mysqldump --compact --uroot --ppass mydatabase mydable >test.sql
from a controller.
If there isn't, do you know a way how to dump data from tables in Zend Framework?
update:
I've found a way here http://www.zfsnippets.com/snippets/view/id/68
There's no direct exec() support in the zend framework. the closest to command line support there is the Zend_Console class, but it's meant for getting arguments from the command line.
I would wrap the exec() function as a process object and work with that. Here's a nice example from the php docs:
<?php
// You may use status(), start(), and stop(). notice that start() method gets called automatically one time.
$process = new Process('ls -al');
// or if you got the pid, however here only the status() metod will work.
$process = new Process();
$process.setPid(my_pid);
?>
<?php
// Then you can start/stop/ check status of the job.
$process.stop();
$process.start();
if ($process.status()){
echo "The process is currently running";
}else{
echo "The process is not running.";
}
?>
<?php
/* An easy way to keep in track of external processes.
* Ever wanted to execute a process in php, but you still wanted to have somewhat controll of the process ? Well.. This is a way of doing it.
* #compability: Linux only. (Windows does not work).
* #author: Peec
*/
class Process{
private $pid;
private $command;
public function __construct($cl=false){
if ($cl != false){
$this->command = $cl;
$this->runCom();
}
}
private function runCom(){
$command = 'nohup '.$this->command.' > /dev/null 2>&1 & echo $!';
exec($command ,$op);
$this->pid = (int)$op[0];
}
public function setPid($pid){
$this->pid = $pid;
}
public function getPid(){
return $this->pid;
}
public function status(){
$command = 'ps -p '.$this->pid;
exec($command,$op);
if (!isset($op[1]))return false;
else return true;
}
public function start(){
if ($this->command != '')$this->runCom();
else return true;
}
public function stop(){
$command = 'kill '.$this->pid;
exec($command);
if ($this->status() == false)return true;
else return false;
}
}
?>
It's also let you stop and check the status of a job.