月度归档:2016年01月

Node.js 安装

Node.js运行环境的部署安装是非常简单的,从https://nodejs.org/en/download/(https://nodejs.org/dist/)下载不同平台编译好的二进制包(也可以下载源码编译,Windows下需要下载Windows Installer (.msi)安装文件,里面包含npm包;如果下载Windows Binary (.exe)则仅仅对应node.exe文件。安装第三方包需要npm支持),解压放入对应目录即可,在CentOS/Ubuntu下,可以释放到/usr/local下,由于PATH默认包含/usr/local/bin目录,换句话说只要解压缩就完成了安装:

cd /usr/local
wget https://nodejs.org/dist/v6.11.3/node-v6.11.3-linux-x64.tar.xz
#xz命令解压xz包得到tar包
xz -d node-v6.11.3-linux-x64.tar.xz
#解压tar包
tar -xvf node-v6.11.3-linux-x64.tar.xz

##或者用tar一键解压
tar xvJf node-v6.11.3-linux-x86.tar.xz

#直接拷贝释放到/usr/local
chown -hR root:root node-v6.11.3-linux-x86
cd node-v6.11.3-linux-x86
cp -frap * /usr/local

直接释放到/usr/local就可以完成安装。由于/usr/local/bin是在PATH中的,所以bin中的node和npm自然是可以直接找到的。

node -v
npm -v

#如果在国内部署,可以使用npm安装cnpm:(https://github.com/cnpm/cnpm)
npm install cnpm -g --registry=https://registry.npm.taobao.org	

使用npm或cnpm安装cheerio(https://github.com/cheeriojs/cheerio)
npm install cheerio
cnpm install cheerio

NPM是一个包管理器,NMP本身就可以看做是一个NodeJS模块,全局安装在/usr/lib/node_modules/中(nmp目录),NPM使用到的包,放入到子目录node_modules中,这个目录中的包就类似是nmp包的本地安装。

如下,升级NMP:

npm install npm -g

参数-g表示全局安装,就是放入到/usr/lib/node_modules/,否则就是本地安装。npm install npm本身就说明npm就是nodejs的一个包。

举例来说:

npm install express

就会在当前目录下创建一个叫node_modules目录,里面安装express包(它还会依赖其它包,会把依赖也下载),这里里面的包,只需要使用require进来即可(实际就是自动进入这个目录去寻找包)

npm install xxx -g
npm install xxx
npm uninstall xxx -g
npm uninstall xxx
npm update xxx
npm search xxx
npm ls -g
npm ls

npm search express
npm install                     #使用package.json文件来安装包
npm install express             #安装指定包
npm install express@0.1.1       #安装指定包指定版本
npm install ../module.tgz       #安装本地包

npm install express -g
npm remove express
npm pack                        #对一个包进行本地打包
npm view express
npm publish
npm unpublish module

对于每个包,package.json是必须的,它定义了包的属性,比如名称、版本、依赖等。更加详细的内容需要去参考官方文档。

代码范例收集

// 数字1-9, 找出9位数,使得其从左边开始,每第n(1<=n<=9)位组成的数字都能被n整除
class Cat {
	public $result = [];
	
	public function c($ss, array $aa, $count) {


		foreach($aa as $a){
			$tmp = $ss.$a;
			
			if(((int)$tmp % $count) === 0){
				$bb = array_diff($aa,[$a]);

				$this->c($tmp,$bb,$count+1);
			}
		}
		if(empty($aa)){
			$this->result[] = $ss;
		}

		return $this;
	}

	public function getResult() {
		return $this->result;
	}
}


$cat = (new Cat())->c('', ['1','2','3','4','5','6','7','8','9'], 1)->getResult();
print_r($cat);

Laravel 任务调度

Laravel中提供了一个任务调度实现,基本实现原理大体并不复杂,依赖操作系统的Crontab服务,每分钟运行一次schedule:run命令,然后判断到期任务,需要注意的是,如果schedule:run命令不是每分钟执行一次,那么调度就有可能有问题,比如:

0-59/3 * * * * 		php /mnt/www/ebt/artisan schedule:run 1>> /dev/null 2>&1

如下调度:

    protected function schedule(Schedule $schedule)
    {
        $schedule->command('test:test2')
                 ->cron('0-59/2 * * * *')
		 ->sendOutputTo("/home/www/schedule.txt");
    }

这个调度本意是每两分钟执行一次,而调度命令是3分钟执行一次,所以无法符合预期。从输出的情况来看,30分和36分执行了一次test:test2命令,那么就基本可以肯定,所谓的调度,实际就是根据当前时间,比对分钟数字,比如设置每两分钟执行一次,那么就比对调度命令被运行时的分钟数是不是2的倍数,其它的情况也是类似的。这个是最简单的实现方案了。所以,调度程序运行需要设置为每分钟执行一次。

以下示例:

<?php

namespace App\Console;

use DB;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;

class Kernel extends ConsoleKernel{
    /**
     * 应用提供的Artisan命令
     *
     * @var array
     */
    protected $commands = [
        'App\Console\Commands\Inspire',
    ];

    /**
     * 定义应用的命令调度
     *
     * @param  \Illuminate\Console\Scheduling\Schedule  $schedule
     * @return void
     */
    protected function schedule(Schedule $schedule)
    {
        // 闭包
        $schedule->call(function () {
            DB::table('recent_users')->delete();
        })->daily();

        // Artisan命令
        $schedule->command('emails:send --force')->daily();

        // 系统命令
        $schedule->exec('node /home/forge/script.js')->daily();
    }
}

可用方法列表:

->cron('* * * * *');
->everyMinute();
->everyFiveMinutes();
->everyTenMinutes();
->everyThirtyMinutes();
->hourly();
->daily();
->dailyAt('13:00');
->twiceDaily(1, 13);
->weekly();
->monthly();

额外的调度约束列表:
->weekdays();
->sundays();
->mondays();
->tuesdays();
->wednesdays();
->thursdays();
->fridays();
->saturdays();
->when(Closure);

大体上,对应Crontab的设置。这里的when()方法接收一个闭包函数,当这个函数返回true时,才执行。如果使用Crontab调度,就需要在运行脚本里面做控制。

由于这个任务调度器实际就是一个启动其它命令的命令,所以对于判断重复运行是很容易做到的,比如上一次运行没有结束,那么当前虽然也满足了运行的条件,也不去运行它,这个在Crontab中也是做不到的(需要在实际运行命令中控制):

$schedule->command('emails:send')->everyMinute()->withoutOverlapping();

方法withoutOverlapping()控制重复运行。

运行结果输出(结果输出到指定文件):

$schedule->command('emails:send')
         ->daily()
         ->sendOutputTo($filePath);

// 发邮件,需要先调用sendOutputTo
// emailOutputTo和sendOutputTo方法只对command方法有效,不支持call方法
$schedule->command('foo')
         ->daily()
         ->sendOutputTo($filePath)
         ->emailOutputTo('foo@example.com');

预留钩子:

$schedule->command('emails:send')
         ->daily()
         ->before(function () {
             // Task is about to start...
         })
         ->after(function () {
             // Task is complete...
         });