Advertisement
  1. Code
  2. Yii

Cómo Programar Con Yii2: Ejecutando Servicios Cron

Scroll to top
Read Time: 8 min
This post is part of a series called How to Program With Yii2.
How to Program With Yii2: ActiveRecord
Programming With Yii2: Building a RESTful API

Spanish (Español) translation by Rafael Chavarría (you can also view the original English article)

Final product imageFinal product imageFinal product image
What You'll Be Creating

Si estás preguntando, "¿Qué es Yii?" revisa mi tutorial anterior: Introducción al Framework Yii, el cuál revisa los beneficios de Yii e incluye un vistazo general de qué hay de nuevo en Yii 2.0, liberado en Octubre de 2014.

En esta serie Programando Con Yii2, estoy guiando a los lectores en el uso del Framework Yii2 para PHP. En el tutorial de hoy, compartiré contigo como sacar ventaja de la capacidad de la consola de Yii para ejecutar trabajos cron.

En el pasado, he usado wget en mis trabajos cron---una URL accesible desde web ejecutaría mis tareas en segundo plano. Esto elevó los asuntos de seguridad y tiene algunos problemas de desempeño. Mientras que abordé algunas maneras de mitigar los riesgos en episodios de nuestra serie startup en seguridad, esperaba hacer transición a comandos llevados por consola. Y con Yii2 es bastante sencillo.

Para el ejemplo de hoy, demostraré comandos cron basados en consola en mi sitio Twixxtr el cuál describí en este episodio Twitter API. Debido a límites de taza y problemas de desempeño de administración, la API Twitter es muy dependiente de tareas cron eficientes y confiables. Así que es un gran ejemplo para compartir contigo.

Antes de que comience, reiteraré: siempre aprecio tus ideas y retroalimentación. Si tienes una pregunta o sugerencia de tema, por favor publica tus ideas en los comentarios de abajo. También puedes contactarme en Twitter @reifman directamente.

¿Qué Es Cron?

Wikipedia describe cron como "un programador de trabajos basado en tiempo en sistemas operativos computacionales parecidos a Unix." Y eso es bastante preciso. Básicamente, cron ejecuta todas las tareas en segundo plano que necesitamos para ejecutar servicios web, desde administración de registros y respaldos hasta peticiones API para limpieza de base de datos.

Para ver tus trabajos cron existentes en un servidor, usualmente tecleas sudo crontab -l y ves algo como esto:

1
# Edit this file to introduce tasks to be run by cron.

2
# 

3
# Each task to run has to be defined through a single line

4
# indicating with different fields when the task will be run

5
# and what command to run for the task

6
# 

7
# To define the time you can provide concrete values for

8
# minute (m), hour (h), day of month (dom), month (mon),

9
# and day of week (dow) or use '*' in these fields (for 'any').# 

10
# Notice that tasks will be started based on the cron's system

11
# daemon's notion of time and timezones.

12
# 

13
# Output of the crontab jobs (including errors) is sent through

14
# email to the user the crontab file belongs to (unless redirected).

15
# 

16
# For example, you can run a backup of all your user accounts

17
# at 5 a.m every week with:

18
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/

19
# 

20
# For more information see the manual pages of crontab(5) and cron(8)

21
# 

22
# m h  dom mon dow   command

23
*/3 * * * * wget -O /dev/null https://meetingplanner.io/daemon/frequent
24
*/15 * * * * wget -O /dev/null http://meetingplanner.io/daemon/quarter
25
0 * * * * wget -O /dev/null http://meetingplanner.io/daemon/hourly
26
15 1 * * * wget -O /dev/null http://meetingplanner.io/daemon/overnight
27
40 2 * * * /usr/sbin/automysqlbackup
28
15 3 * * 5 wget -O /dev/null http://meetingplanner.io/daemon/weekly
29
30 2 * * 1 /opt/letsencrypt/letsencrypt-auto renew >> /var/log/le-renew.log

El lado izquierdo especifica activar estas tareas cada 3 o 15 minutos o diariamente a media noche, etc., y el lado derecho es el script a ejecutar. Mira también Programando Tareas Con Trabajos Cron (Envato Tuts+).

Nota cómo el script Let's Encrypt es un comando de consola único. Este se ejecuta desde la línea de comando en nuestro servidor. Sin embargo, todas mis tareas de Planificador de Reuniones de arriba se ejecutan vía wget. Eso actúa como si un robot estuviera en un navegador web em un horario específico contra nuestra aplicación web que realiza tareas en segundo plano.

En adición a los gastos generales que una petición web externa requiere y las limitaciones de tiempo muerto en scripts en servidores, tienes que asegurar estos puntos de acceso. Aquí está un ejemplo de cómo lo hace Planificador de Reuniones:

1
// only cron jobs and admins can run this controller's actions

2
    public function beforeAction($action)
3
    {
4
      // your custom code here, if you want the code to run before action filters,

5
      // which are triggered on the [[EVENT_BEFORE_ACTION]] event, e.g. PageCache or AccessControl

6
      if (!parent::beforeAction($action)) {
7
          return false;
8
      }
9
      // other custom code here

10
      if (( $_SERVER['REMOTE_ADDR'] == $_SERVER['SERVER_ADDR'] ) ||
11
          (!\Yii::$app->user->isGuest && \common\models\User::findOne(Yii::$app->user->getId())->isAdmin()))
12
       {
13
         return true;
14
       }
15
      return false; // or false to not run the action

16
    }

Este verifica que el usuario haya iniciado sesión como un administrador o ejecutando localmente en el servidor en una dirección IP de Internet idéntica.

Implementado Comandos Cron Basado en Consola

Alex Makarov, uno de los voluntarios líderes detrás del desarrollo del Framework Yii, ha sido de utilidad repondiéndome preguntas mientras escribo regularmente sobre el framework para Envato Tuts+. Después de leer mi episodio de seguridad, el preguntó por qué no estaba usando la capacidad de consola inherente de Yii2 para trabajos cron. Básicamente, yo no sabía de ella.

Así como tenía un /frontend/controllers/DaemonController.php, creé un /console/controllers/DaemonController.php. Para este tutorial, haré esto para el más pequeño y simple servicio web Twixxr.

Estoy acostumbrado a usar la consola para ejecutar migraciones de bases de datos (ej. ./yii migrate/up 7), pero eso es todo. Estaba ansioso por probar usarlo para tareas en segundo plano.

Como lo escribí en un tutorial anterior, mi recién nacido sitio Twixxr requiere procesos extensivos en segundo plano para rotar regularmente llamadas API para todas las peticiones de usuario para ofrecer amistas a cuentas influyentes de Twitter pertenecientes a mujeres.

Aquí está cómo luce la página de inicio:

How to Program with Yii2 - Console-Based Cron - Twixxr Home Page Example WebsiteHow to Program with Yii2 - Console-Based Cron - Twixxr Home Page Example WebsiteHow to Program with Yii2 - Console-Based Cron - Twixxr Home Page Example Website

Así que pensé que Twixxr haría un gran lecho de prueba para ejecutar un controlador cron basado en consola.

El Nuevo DaemonController.php

Aquí está el núcleo de mi nuevo DaemonController.php basado en consola:

1
<?php
2
namespace console\controllers;
3
4
use Yii;
5
use yii\helpers\Url;
6
use yii\console\Controller;
7
use frontend\models\Twixxr;
8
9
/**

10
 * Test controller

11
 */
12
class DaemonController extends Controller {
13
14
    public function actionIndex() {
15
        echo "Yes, cron service is running.";
16
    }
17
18
    public function actionFrequent() {
19
      // called every two minutes

20
      // */2 * * * * ~/sites/www/yii2/yii test

21
      $time_start = microtime(true);
22
      $x = new \frontend\models\Twixxr();
23
      $x->process($time_start);
24
      $time_end = microtime(true);
25
      echo 'Processing for '.($time_end-$time_start).' seconds';
26
    }
27
28
    public function actionQuarter() {
29
        // called every fifteen minutes

30
        $x = new \frontend\models\Twixxr();
31
        $x->loadProfiles();
32
      }
33
34
      public function actionHourly() {
35
        // every hour

36
        $current_hour = date('G');
37
        if ($current_hour%4) {
38
          // every four hours

39
        }
40
            if ($current_hour%6) {
41
            // every six hours

42
          }
43
        }

Nota que es prácticamente idéntico a la estructura de mi controlador basado en front-end, pero es seguramente inaccesible a la web porque está en el árbol /console. Ningún servidor web Apache está configurado para navegar esta área.

Así qué, en el ejemplo de arriba, actionFrequent() será llamado cada dos o tres minutos. Este procesa otro conjunto de peticiones de amistad Twixxr. Por otro lado, actionQuarter() es llamado cada 15 minutos y actualiza la información de perfil para cuentas navegando. Veamos cómo funciona la programación en el archivo cron.

El Nuevo Archivo Crontab

Esencialmente, en mi archivo crontab, reemplazo wget con un script Linux directo como se muestra arriba para renovaciones Let's Encrypt.

Tecleas sudo crontab -e para editar o -l para listar sus contenidos. Aquí está mi archivo cron Twixxr:

1
$ sudo crontab -l
2
# m h  dom mon dow   command

3
*/3 * * * * /var/www/twixxr/yii daemon/frequent
4
*/15 * * * * /var/www/twixxr/yii daemon/quarter
5
0 * * * * /var/www/twixxr/yii daemon/hourly
6
15 1 * * * /var/www/twixxr/yii daemon/overnight
7
15 3 * * 5 /var/www/twixxr/yii daemon/weekly
8
#40 2 * * * /usr/sbin/automysqlbackup

9
30 2 * * 1 /usr/bin/letsencrypt renew >> /var/log/le-renew.log

Es bastante simple. El lado izquierdo de /var/www/twixxr/yii daemon/frequent es la ruta en donde vive el intérprete yii, y el lado derecho es el controlador y método de la consola a llamar.

Todo funcionó bastante bien cambiando. No he cambiado Planificador de Reuniones todavia ya que quiero hacer más pruebas. Cuando las tareas en segundo plano se quiebran, es difícil saberlo y depurarlas (aunque Sentry error logging está ayudando mucho).

Problemas a Considerar

Un elemento con el que me encontré es que el namespace de la consola es distinto al namespace del front-end--- así qué, por ejemplo, el componente SiteHelper.php que establecí en mi tutorial, que describió ejecutando múltiples sitios desde una sola base de código, falló cuando lo invoqué. Quitarlo funcionó, pero necesite ejecutar pruebas para asegurar que el código subyacente de fondo aún funcionaba. Sin embargo, la mayoría del intercambio salió bien.

Como con cualquier otro cambio de código, prueba y monitorea a fondo.

Qué Sigue

Viendo hacia adelante, exploraré construir APIs REST dentro del framework Yii2, el cuál depende coincidentemente en crear un sub-árbol distinto como el árbol de consola pero para APIs externas. Por supuesto, esto trae problemas complejos de autenticación y seguridad... así que será divertido explorar estos contigo. Estaré viendo APIs desde varios ángulos. Estoy en realidad bastante emocionado sobre esto.

Espera los siguientes tutoriales en mi serie Programando Con Yii2 mientras continuo sumergiéndome en diferentes aspectos del framework. Por favor también explora la serie Construyendo Tu Startup Con PHP, que documento el proceso de construir Simple Planner y Planificador de Reuniones.

Si quisieras saber cuando llega el siguiente tutorial Yii2, sígueme en Twitter @reifman o revisa mi página de instructor para actualizaciones.

Enlaces Relacionados

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.