Como executar um trabalho cron dentro de um contêiner de docker?


275

Estou tentando executar um cronjob dentro de um contêiner de docker que chama um script de shell.

Ontem, estive pesquisando por toda a web e estouro de pilha, mas não consegui realmente encontrar uma solução que funcione.
Como posso fazer isso?

EDITAR:

Eu criei um repositório (comentado) do github com um contêiner cron de docker em funcionamento que chama um script de shell em um determinado intervalo.

Respostas:


365

Você pode copiar seu crontab em uma imagem, para que o contêiner lançado a partir dessa imagem execute o trabalho.

Consulte " Executar um trabalho cron com o Docker " de Julien Boulay no seguinte Ekito/docker-cron:

Vamos criar um novo arquivo chamado " hello-cron" para descrever nosso trabalho.

* * * * * echo "Hello world" >> /var/log/cron.log 2>&1
# An empty line is required at the end of this file for a valid cron file.

O Dockerfile a seguir descreve todas as etapas para criar sua imagem

FROM ubuntu:latest
MAINTAINER docker@ekito.fr

RUN apt-get update && apt-get -y install cron

# Copy hello-cron file to the cron.d directory
COPY hello-cron /etc/cron.d/hello-cron

# Give execution rights on the cron job
RUN chmod 0644 /etc/cron.d/hello-cron

# Apply cron job
RUN crontab /etc/cron.d/hello-cron

# Create the log file to be able to run tail
RUN touch /var/log/cron.log

# Run the command on container startup
CMD cron && tail -f /var/log/cron.log

(veja Gaafar 's comentário e Como eu faço apt-getinstalar menos ruidoso? :
apt-get -y install -qq --force-yes cronpode trabalhar também)

Como observado por Nathan Lloyd nos comentários :

Nota rápida sobre uma pegadinha:
Se você estiver adicionando um arquivo de script e instruindo o cron a executá-lo, lembre-se de que o Cron falha silenciosamente, se você esquecer .
RUN chmod 0744 /the_script


OR, verifique se o trabalho em si redirecionar diretamente para stdout / stderr em vez de um arquivo de log, conforme descrito na hugoShaka 's resposta :

 * * * * * root echo hello > /proc/1/fd/1 2>/proc/1/fd/2

Substitua a última linha do Dockerfile por

CMD ["cron", "-f"]

Veja também (about cron -f, ou seja, cron "foreground") " docker ubuntu cron -fnão está funcionando "


Crie e execute:

sudo docker build --rm -t ekito/cron-example .
sudo docker run -t -i ekito/cron-example

Seja paciente, aguarde 2 minutos e sua linha de comando deve exibir:

Hello world
Hello world

Eric acrescenta nos comentários :

Observe que tailtalvez não seja exibido o arquivo correto se ele for criado durante a criação da imagem.
Se for esse o caso, você precisará criar ou tocar no arquivo durante o tempo de execução do contêiner para que o tail selecione o arquivo correto.

Consulte "A saída de tail -fno final de uma janela de encaixe CMDnão está aparecendo ".


1
Primeiro tive que instalar o cron, pois não está incluído. Mas, adicionando isso ao Dockerfile, ele funciona. Obrigado! RUN apt-get update && apt-get install cron
C Heyer

2
você provavelmente deve adicionar -yà instalação do cron para evitar a saída do docker build
gafi

1
@Gaafar Right! Incluímos seu comentário na resposta para obter mais visibilidade e adicionei outra opção.
VonC 16/10

6
Essa solução ainda funciona? Quando sigo as diretrizes fornecidas, quando entro no contêiner como root e digito crontab -l, não recebo o crontab instalado para root , também, minha tela permanece em branco. No entanto, quando eu checo '/etc/cron.d/', vejo que o crontab fiel está lá (e, ainda mais surpreendente), quando checo /var/log/cron.log, vejo que o script está em execução (o conteúdo do arquivo está sendo anexado Hello World). Eu estou puxando esta imagem na minha Dockerfile: FROM phusion/baseimage:0.10.0. Alguma idéia sobre a discrepância de comportamento?
Homunculus Reticulli

11
A partir de 2018, essa abordagem não funcionará mais; alguém conseguiu que seu cronjob funcionasse com o Ubuntu como a imagem base? Não estou interessado na imagem alpina que vem com o cron ficando fora da caixa #
pelican

148

A solução adotada pode ser perigosa em um ambiente de produção .

Na janela de encaixe, você deve executar apenas um processo por contêiner porque, se não o fizer, o processo que bifurcou e ficou em segundo plano não é monitorado e pode parar sem que você saiba.

Quando você usa CMD cron && tail -f /var/log/cron.logo processo cron basicamente bifurca-se para executar cronem segundo plano, o processo principal sai e permite executar tailfem primeiro plano. O processo cron em segundo plano pode parar ou falhar e você não notará, seu contêiner continuará sendo executado silenciosamente e sua ferramenta de orquestração não o reiniciará.

Você pode evitar isso redirecionando diretamente os comandos do cron para a janela de encaixe stdoute stderrque estão localizados respectivamente em /proc/1/fd/1e /proc/1/fd/2.

Usando redirecionamentos básicos do shell, você pode fazer algo assim:

* * * * * root echo hello > /proc/1/fd/1 2>/proc/1/fd/2

E seu CMD será: CMD ["cron", "-f"]


14
Nice: cron -fé para "cron foreground". Eu incluí sua resposta na minha acima, para mais visibilidade. +1
VonC

Digamos que meu programa não produz nada. Ainda posso usar esse método e ter certeza de que meu processo não será interrompido em segundo plano?
Arcsector

1
@Arcsector Este método evita colocar um processo em segundo plano, por isso não falha silenciosamente. Ter um processo em segundo plano em um contêiner de janela de encaixe não é simples. Se você deseja ter um processo em segundo plano em execução, convém usar um processo init para monitorar os vários processos executados no contêiner. Outra maneira é iniciar o processo em outro contêiner próximo ao principal chamado 'sidecar'. Geralmente, a melhor maneira é evitar vários processos no contêiner.
HugoShaka #

Legal e Limpo ! Love it :)
AmaelH

1
Esta é uma boa solução e funciona bem para nós, além de um problema. Quando o contêiner recebe um sinal do SIGTERM, ele não parece esperar o término do processo agendado e o desligamento normal, mas sim o processo que pode causar problemas.
James Hulse

107

Para quem deseja usar uma imagem simples e leve:

FROM alpine:3.6

# copy crontabs for root user
COPY config/cronjobs /etc/crontabs/root

# start crond with log level 8 in foreground, output to stderr
CMD ["crond", "-f", "-d", "8"]

Onde cronjobs é o arquivo que contém seus cronjobs, neste formato:

* * * * * echo "hello stackoverflow" >> /test_file 2>&1
# remember to end this file with an empty new line

10
Imagem simples, leve e baseada em imagem. Essa deve ser a resposta aceita. Também use o > /proc/1/fd/1 2> /proc/1/fd/2redirecionamento para acessar a saída dos cronjobs diretamente dos logs da janela de encaixe.
precisa saber é o seguinte

2
Para pessoas que não usam alpino: O crond que suporta o -d 8parâmetro não é o cron padrão, é o comando crond do busybox. Por exemplo, no ubuntu, você pode executar isso como busybox crond -f -d 8. Para versões mais antigas, você precisa usar -L /dev/stdout/.
Trendfischer

2
Eu daria este 100 se eu pudesse. Essa é de longe a melhor maneira de executar tarefas cron em um ambiente Docker.
Jitsusama #

1
Se você não deseja construir uma nova imagem toda vez que alterar o trabalho do cron (ou se precisar de vários), basta executar o Alpine e usar um volume para definir o cron. Eu testei-lo usando o seguinte: docker run -v ${PWD}/cronjobs:/etc/crontabs/root alpine:3.6 crond -f -d 8. @Groostav, você pode usar uma coisa semelhante no Docker Compose.
duality_

1
CMD ["crond"ou CMD ["cron"?
codemith 17/06

38

O que o @VonC sugeriu é bom, mas eu prefiro fazer toda a configuração de tarefas cron em uma linha. Isso evitaria problemas de plataforma cruzada, como o local do cronjob, e você não precisa de um arquivo cron separado.

FROM ubuntu:latest

# Install cron
RUN apt-get -y install cron

# Create the log file to be able to run tail
RUN touch /var/log/cron.log

# Setup cron job
RUN (crontab -l ; echo "* * * * * echo "Hello world" >> /var/log/cron.log") | crontab

# Run the command on container startup
CMD cron && tail -f /var/log/cron.log

Depois de executar o contêiner do docker, verifique se o serviço cron está funcionando:

# To check if the job is scheduled
docker exec -ti <your-container-id> bash -c "crontab -l"
# To check if the cron service is running
docker exec -ti <your-container-id> bash -c "pgrep cron"

Se você preferir ter ENTRYPOINT em vez de CMD, poderá substituir o CMD acima por

ENTRYPOINT cron start && tail -f /var/log/cron.log

1
Alternativa interessante. 1
VonC 6/17/17

2
RUN apt-get update && apt-get -y install cronou então não será capaz de encontrar o pacotecron
alphabetasoup

2
Graças Youness, você me deu a idéia de fazer o seguinte, que trabalhou no meu caso onde cada cron é especificado em um arquivo diferente: RUN cat $APP_HOME/crons/* | crontab como um encanto :)
marcostvz

adicionar crona um script de ponto de entrada parece ser a melhor opção: ENTRYPOINT ["entrypoint.sh"]
bozdoz

20

Há outra maneira de fazer isso: usar o Tasker , um executor de tarefas que possui suporte ao cron (um agendador).

Por quê ? Às vezes, para executar um trabalho cron, você precisa misturar sua imagem base (python, java, nodejs, ruby) com a base. Isso significa outra imagem para manter. Tasker evite isso dissociando a crond e o contêiner. Você pode se concentrar apenas na imagem que deseja executar seus comandos e configurar o Tasker para usá-la.

Aqui está um docker-compose.ymlarquivo, que executará algumas tarefas para você

version: "2"

services:
    tasker:
        image: strm/tasker
        volumes:
            - "/var/run/docker.sock:/var/run/docker.sock"
        environment:
            configuration: |
                logging:
                    level:
                        ROOT: WARN
                        org.springframework.web: WARN
                        sh.strm: DEBUG
                schedule:
                    - every: minute
                      task: hello
                    - every: minute
                      task: helloFromPython
                    - every: minute
                      task: helloFromNode
                tasks:
                    docker:
                        - name: hello
                          image: debian:jessie
                          script:
                              - echo Hello world from Tasker
                        - name: helloFromPython
                          image: python:3-slim
                          script:
                              - python -c 'print("Hello world from python")'
                        - name: helloFromNode
                          image: node:8
                          script:
                              - node -e 'console.log("Hello from node")'

Existem 3 tarefas lá, todas elas serão executadas a cada minuto ( every: minute) e cada uma delas executará o scriptcódigo, dentro da imagem definida emimage seção.

Apenas corra docker-compose upe veja-o funcionando. Aqui está o repositório Tasker com a documentação completa:

http://github.com/opsxcq/tasker


A Dockerception (executando contêineres do Docker de outro contêiner) é uma prática recomendada e deve se limitar à integração contínua. Uma solução alternativa seria usar docker execem contêineres especificados.
precisa saber é o seguinte

1
O Tasker não usa a janela de encaixe na janela de encaixe (Dind / Dockerception), observe que é passado no soquete da janela de encaixe como um mapeamento, todos os contêineres gerados são gerados no daemon que o tasker executa. E se você não deseja executar o tasker dentro da janela de encaixe, basta implantá-lo como qualquer outro aplicativo.
OPSXCQ

1
Não tenho as vantagens de usar o tasker. Parece realmente um exagero para mim usar java e sh *** apenas para executar um trabalho cron.
Karl Adler

A mistura de cron e a imagem base que você precisa (python / nó por exemplo) cria uma dependência extra que precisa ser mantida e implantada. Nesse cenário, todos os trabalhos compartilham o mesmo contêiner, isso significa que você precisa se preocupar em limpar tudo depois todo trabalho é executado. Os trabalhos executados no tasker são idempotentes, portanto você tem menos motivos para se preocupar.
OPSXCQ

13

A resposta de VonC é bastante completa. Além disso, gostaria de acrescentar uma coisa que me ajudou. Se você quiser apenas executar um trabalho cron sem seguir um arquivo, ficará tentado a remover o&& tail -f /var/log/cron.log comando cron.

No entanto, isso fará com que o contêiner do Docker saia logo após a execução, porque quando o comando cron é concluído, o Docker acha que o último comando foi encerrado e, portanto, mata o contêiner. Isso pode ser evitado executando cron em primeiro plano via cron -f.


9

Embora isso pretenda executar tarefas ao lado de um processo em execução em um contêiner via execinterface do Docker , isso pode ser do seu interesse.

Eu escrevi um daemon que observa contêineres e agenda trabalhos, definidos em seus metadados, neles. Exemplo:

version: '2'

services:
  wordpress:
    image: wordpress
  mysql:
    image: mariadb
    volumes:
      - ./database_dumps:/dumps
    labels:
      deck-chores.dump.command: sh -c "mysqldump --all-databases > /dumps/dump-$$(date -Idate)"
      deck-chores.dump.interval: daily

Também é possível uma configuração 'clássica', semelhante ao cron.

Aqui estão os documentos , o repositório de imagens .


Obrigado. Esta resposta é a mais adequada para o ambiente de contêineres do Docker. Nenhuma alteração nas imagens do Docker, apenas adicionando contêiner especial para a execução de tarefas, funciona como comando docker exec <container_name> <some_command>por agendamento.
PRIHLOP 6/10/19

Essa é a resposta mais simples e limpa, "faça o trabalho".
Ibrahim Awad

9

Criei uma imagem do Docker com base nas outras respostas, que podem ser usadas como

docker run -v "/path/to/cron:/etc/cron.d/crontab" gaafar/cron

where /path/to/cron: caminho absoluto para o arquivo crontab ou você pode usá-lo como base em um Dockerfile:

FROM gaafar/cron

# COPY crontab file in the cron directory
COPY crontab /etc/cron.d/crontab

# Add your commands here

Para referência, a imagem está aqui .


Imagem interessante. +1
VonC

5

Ao implantar seu contêiner em outro host, observe que ele não iniciará nenhum processo automaticamente. Você precisa garantir que o serviço 'cron' esteja sendo executado dentro do seu contêiner. No nosso caso, estou usando o Supervisord com outros serviços para iniciar o serviço cron.

[program:misc]
command=/etc/init.d/cron restart
user=root
autostart=true
autorestart=true
stderr_logfile=/var/log/misc-cron.err.log
stdout_logfile=/var/log/misc-cron.out.log
priority=998

Recebo um erro no supervisor.log que o serviço cron parou várias vezes e entrou no estado FATAL. No entanto, o cron parece estar rodando no topo e executando cronjobs normalmente. Obrigado por isso!
Lephleg

Sim, a mesma coisa aconteceu comigo também, mas funciona normalmente, por isso não precisa se preocupar.
Sagar Ghuge

5

Defina o cronjob em um contêiner dedicado que executa o comando via docker exec no seu serviço.

Isso é maior coesão e o script em execução terá acesso às variáveis ​​de ambiente que você definiu para o seu serviço.

#docker-compose.yml
version: "3.3"
services:
    myservice:
      environment:
        MSG: i'm being cronjobbed, every minute!
      image: alpine
      container_name: myservice
      command: tail -f /dev/null

    cronjobber:
     image: docker:edge
     volumes:
      - /var/run/docker.sock:/var/run/docker.sock
     container_name: cronjobber
     command: >
          sh -c "
          echo '* * * * * docker exec myservice printenv | grep MSG' > /etc/crontabs/root
          && crond -f"

Não pude fazer isso funcionar usando o docker swarm. Obtendo myservice unknownerros.
Mark Grimes

Deve haver um aviso sobre o impacto de alta segurança de montagem um socket janela de encaixe tem: lvh.io/posts/...
ocasional

4

Se você estiver usando o Docker para Windows, lembre-se de que você precisa alterar o formato de final de linha de CRLF para LF (ou seja, do DOS para o Unix) se pretender importar o arquivo crontab do Windows para o contêiner ubuntu. Caso contrário, seu cron-job não funcionará. Aqui está um exemplo de trabalho:

FROM ubuntu:latest

RUN apt-get update && apt-get -y install cron
RUN apt-get update && apt-get install -y dos2unix

# Add crontab file (from your windows host) to the cron directory
ADD cron/hello-cron /etc/cron.d/hello-cron

# Change line ending format to LF
RUN dos2unix /etc/cron.d/hello-cron

# Give execution rights on the cron job
RUN chmod 0644 /etc/cron.d/hello-cron

# Apply cron job
RUN crontab /etc/cron.d/hello-cron

# Create the log file to be able to run tail
RUN touch /var/log/hello-cron.log

# Run the command on container startup
CMD cron && tail -f /var/log/hello-cron.log

Na verdade, isso me levou horas para descobrir, pois a depuração de tarefas cron em contêineres de docker é uma tarefa tediosa. Espero que ajude outras pessoas que não conseguem obter o código para o trabalho!


3

Dos exemplos acima, criei esta combinação:

Imagem e edição alpina usando o Crontab no Nano (eu odeio vi)

FROM alpine

RUN apk update
RUN apk add curl nano

ENV EDITOR=/usr/bin/nano 

# start crond with log level 8 in foreground, output to stderr
CMD ["crond", "-f", "-d", "8"]

# Shell Access
# docker exec -it <CONTAINERID> /bin/sh

# Example Cron Entry
# crontab -e
# * * * * * echo hello > /proc/1/fd/1 2>/proc/1/fd/2
# DATE/TIME WILL BE IN UTC

2

Configurar um cron em paralelo a um trabalho único

Crie um arquivo de script, digamos run.sh, com o trabalho que deve ser executado periodicamente.

#!/bin/bash
timestamp=`date +%Y/%m/%d-%H:%M:%S`
echo "System path is $PATH at $timestamp"

Salvar e sair.

Usar ponto de entrada em vez de CMD

Se você tiver vários trabalhos para iniciar durante a contêiner do docker, use o arquivo do ponto de entrada para executá-los todos.

O arquivo do ponto de entrada é um arquivo de script que entra em ação quando um comando de execução do docker é emitido. Portanto, todas as etapas que queremos executar podem ser colocadas nesse arquivo de script.

Por exemplo, temos 2 trabalhos a serem executados:

Executar uma tarefa : echo “O contêiner do Docker foi iniciado”

Executar trabalho periódico : run.sh

Criar entrypoint.sh

#!/bin/bash

# Start the run once job.
echo "Docker container has been started"

# Setup a cron schedule
echo "* * * * * /run.sh >> /var/log/cron.log 2>&1
# This extra line makes it a valid cron" > scheduler.txt

crontab scheduler.txt
cron -f

Vamos entender o crontab que foi configurado no arquivo

* * * * *: Cron horário; o trabalho deve ser executado a cada minuto. Você pode atualizar a programação com base em seus requisitos.

/run.sh: O caminho para o arquivo de script que deve ser executado periodicamente

/var/log/cron.log: O nome do arquivo para salvar a saída do trabalho cron agendado.

2>&1: Os logs de erro (se houver) também serão redirecionados para o mesmo arquivo de saída usado acima.

Nota : Não esqueça de adicionar uma nova linha extra, pois ela é um cron válido. Scheduler.txt: a configuração completa do cron será redirecionada para um arquivo.

Usando variáveis ​​de ambiente específicas do sistema / usuário no cron

Meu trabalho cron real estava esperando a maioria dos argumentos, conforme as variáveis ​​de ambiente passavam para o comando docker run. Mas, com o bash, não pude usar nenhuma das variáveis ​​de ambiente que pertencem ao sistema ou ao contêiner do docker.

Em seguida, isso surgiu como uma solução alternativa para esse problema:

  1. Adicione a seguinte linha no entrypoint.sh
declare -p | grep -Ev 'BASHOPTS|BASH_VERSINFO|EUID|PPID|SHELLOPTS|UID' > /container.env
  1. Atualize a configuração do cron e especifique
SHELL=/bin/bash
BASH_ENV=/container.env

Por fim, você entrypoint.shdeve parecer

#!/bin/bash

# Start the run once job.
echo "Docker container has been started"

declare -p | grep -Ev 'BASHOPTS|BASH_VERSINFO|EUID|PPID|SHELLOPTS|UID' > /container.env

# Setup a cron schedule
echo "SHELL=/bin/bash
BASH_ENV=/container.env
* * * * * /run.sh >> /var/log/cron.log 2>&1
# This extra line makes it a valid cron" > scheduler.txt

crontab scheduler.txt
cron -f

Por último, mas não menos importante: criar um arquivo Docker

FROM ubuntu:16.04
MAINTAINER Himanshu Gupta

# Install cron
RUN apt-get update && apt-get install -y cron

# Add files
ADD run.sh /run.sh
ADD entrypoint.sh /entrypoint.sh

RUN chmod +x /run.sh /entrypoint.sh

ENTRYPOINT /entrypoint.sh

É isso aí. Crie e execute a imagem do Docker!


1
@himanshuIIITian Eu tentei isso, o problema é que o script do "executar uma tarefa" nunca está retornando e também o milho -f não está retornando, então ... isso não está funcionando para mim, tem alguma idéia? obrigado
Doron Levi

@DoronLevi - você pode compartilhar alguns logs para analisar o problema? Ou você pode verificar o código inteiro a partir daqui - github.com/nehabhardwaj01/docker-cron
himanshuIIITian

Obrigado pelo feedback. Fico feliz que a resposta tenha sido útil.
himanshuIIITian

1

Trabalhos Cron são armazenados em / var / spool / cron / crontabs (local comum em todas as distros que eu conheço). BTW, você pode criar uma guia cron no bash usando algo assim:

crontab -l > cronexample
echo "00 09 * * 1-5 echo hello" >> cronexample
crontab cronexample
rm cronexample

Isso criará um arquivo temporário com a tarefa cron e, em seguida, programe-o usando o crontab. A última linha remove o arquivo temporário.


O crondaemon normalmente não é executado em um contêiner.
26516 Matt

@BhargavNanekalva, ele precisa ser configurado especificamente em um contêiner que esta resposta não aborda.
Matt

@ Matt, você poderia indicar exatamente como ele deve ser especificado no contêiner? . Eu faço crontab -l e o comando é mostrado - kagda.ru/i/6d014816d43_29-06-2017-11:38:59_6d01.png, mas ainda não está sendo executado
Tebe

@ Копать_Шо_я_нашел Você precisa executar crondalém do serviço que está executando no contêiner, normalmente com um gerente de serviço como o s6. Provavelmente perguntar isso como uma questão de obter uma resposta adequada
Matt

1

Ao executar em algumas imagens reduzidas que restringem o acesso root, tive que adicionar meu usuário aos sudoers e executar como sudo cron

FROM node:8.6.0
RUN apt-get update && apt-get install -y cron sudo

COPY crontab /etc/cron.d/my-cron
RUN chmod 0644 /etc/cron.d/my-cron
RUN touch /var/log/cron.log

# Allow node user to start cron daemon with sudo
RUN echo 'node ALL=NOPASSWD: /usr/sbin/cron' >>/etc/sudoers

ENTRYPOINT sudo cron && tail -f /var/log/cron.log

Talvez isso ajude alguém


Eu acredito que a imagem do nó usa o usuário do nó; então talvez você
precise

1

Então, meu problema era o mesmo. A correção foi alterar a seção de comando no docker-compose.yml.

De

comando: crontab / etc / crontab && tail -f / etc / crontab

Para

comando: crontab / etc / crontab

comando: tail -f / etc / crontab

O problema foi o '&&' entre os comandos. Depois de excluir isso, tudo estava bem.


-1

A maneira mais robusta que encontrei até agora é executar um contêiner cron independente - instale o cliente docker e monte a meia docker para que você possa conversar com o servidor docker no host.

Em seguida, basta usar env vars para cada tarefa cron e um script de ponto de entrada para gerar o / etc / crontab

Aqui está uma imagem que eu criei usando esse princípio e usando-o em produção nos últimos 3-4 anos.

https://www.vip-consult.solutions/post/better-docker-cron#content


As respostas devem ser auto-suficiente e não conectar a recursos externos
Nicolas Bouliane

-2

Tente usar a gema do relógio para agendar tarefas. Siga as etapas fornecidas neste link.

http://fuzzyblog.io/blog/rails/2017/05/11/adding-cron-to-a-dockerized-rails-application-using-clockwork.html

Você pode chamar a tarefa rake dentro do arquivo lib / clock.rb como abaixo.

every(1.day, 'Import large data from csv files', :at => '5:00') do |job|
  `rake 'portal:import_data_from_csv'`
end

Crie um contêiner separado no arquivo docker-compose e execute o comando abaixo dentro do contêiner.

command: bundle exec clockwork lib/clock.rb

1
Boa idéia de usar outra ferramenta para agendamento. No entanto, esta pergunta foi feita especificamente para o cron, então sua sugestão seria melhor como um comentário para a pergunta na minha opinião.
Richard Kiefer
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.