From 869a9ddf0de7cdce2742367391aeb1ed18598640 Mon Sep 17 00:00:00 2001 From: Ingar Helgesen Date: Mon, 6 Jul 2020 09:48:43 +0200 Subject: [PATCH] Added cron support --- Dockerfile | 4 ++-- README.md | 18 +++++++++++++++++- docker-compose.yml | 7 ++++++- src/index.docker.ts | 46 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 src/index.docker.ts diff --git a/Dockerfile b/Dockerfile index b421707..8f8beb6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,7 +14,7 @@ USER deno # These steps will be re-run upon each file change in your working directory: ADD src/ . # Compile the main app so that it doesn't need to be compiled each startup/entry. -RUN deno cache index.ts +RUN deno cache index*.ts # "deno" is entrypoint, so all commands are arguments to deno -CMD [ "run", "--allow-read", "--allow-write", "--allow-net", "--allow-env", "index.ts" ] \ No newline at end of file +CMD [ "run", "--allow-read", "--allow-run", "--allow-env", "index.docker.ts" ] \ No newline at end of file diff --git a/README.md b/README.md index 2d6c203..43ae7de 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,8 @@ This project's purpose was mostly to test Deno and learn Typescript (I have a lo ## How to use [![Docker stats](https://dockeri.co/image/sherex/ddns-client)](https://hub.docker.com/r/sherex/ddns-client/) ### Docker Compose +Use environment variable `DDNS_CRON` to schedule it. + 1. Create a `docker-compose.yml` file ```yml # docker-compose.yml @@ -20,6 +22,11 @@ version: "3.7" services: ddns_client: container_name: ddns-client + environment: + - GD_KEY=YOUR_KEY_HERE + - GD_SECRET=YOUR_SECRET_HERE + - DDNS_CRON=1 */60 * * * * + - DDNS_LOGLEVEL=info image: sherex/ddns-client:latest volumes: - "./config:/app/config" @@ -37,10 +44,11 @@ $ docker-compose up # -d # Add '-d' switch to run as daemon Check out [configuration](#Configuration) further down. ### Docker +Use environment variable `DDNS_CRON` to schedule it. ```sh # Creates the config directory and places config.json inside # Replace $PWD with %cd% on Windows -$ docker run -v $PWD/config:/app/config --name ddns-client sherex/ddns-client +$ docker run -v $PWD/config:/app/config -d -e "DDNS_CRON=1 */60 * * * *" --name ddns-client sherex/ddns-client # Edit 'config/config.json' - I recommend VSCode to use the JSON schema. @@ -86,6 +94,14 @@ It can be one of the values (case insensitive): The default is `info`. +### Cron +The `index.docker.ts` file starts `index.ts` as a subprocess and exits when it's done. +But if you set the environment variable `DDNS_CRON` to a cron string, it will stay running and start `index.ts` every time the cron string matches. + +The docker container on [Docker Hub](https://hub.docker.com/r/sherex/ddns-client/) uses this file. + +It uses [deno_cron](https://deno.land/x/deno_cron) for the cron jobs. + ## TODO - [X] Move config from .env to config.json - [X] Use config.json diff --git a/docker-compose.yml b/docker-compose.yml index 7d2e78d..eba6188 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,6 +2,11 @@ version: "3.7" services: ddns_client: container_name: ddns-client - image: sherex/ddns-client:latest + environment: + - GD_KEY=YOUR_KEY_HERE + - GD_SECRET=YOUR_SECRET_HERE + - DDNS_CRON=1 */60 * * * * + - DDNS_LOGLEVEL=INFO + build: ./ volumes: - "./config:/app/config" \ No newline at end of file diff --git a/src/index.docker.ts b/src/index.docker.ts new file mode 100644 index 0000000..647a4aa --- /dev/null +++ b/src/index.docker.ts @@ -0,0 +1,46 @@ +import "https://deno.land/x/dotenv/load.ts"; +import { cron, stop, start } from 'https://deno.land/x/deno_cron/cron.ts' +import { log } from './lib/logger.ts' +import { exists } from './lib/exists.ts' + +let mainPath = "index.ts" + +if (exists("./index.ts") === 'file') mainPath = "./index.ts" +else if (exists("./src/index.ts") === 'file') mainPath = "./src/index.ts" + +const cronString = Deno.env.get('DDNS_CRON') +let timesFailed = 0 + +if (cronString) { + log('info', ["index.docker", "start", "with cron", cronString]) + + stop() + await run() // Make sure it runs once when started + start() + + cron(cronString, () => run()) +} else { + stop() + log('info', ["index.docker", "start", "single-run"]) + await run() + Deno.exit(0) +} + +async function run() { + const process = Deno.run({ + cmd: ["deno", "run", "--allow-read", "--allow-write", "--allow-net", "--allow-env", mainPath], + env: Deno.env.toObject() + }) + const status = await process.status() + if (status.code === 0) { + timesFailed = 0 + log('info', ["index.docker", "success"]) + return + } else if (timesFailed < 3) { + timesFailed++ + log('error', ["index.docker", "failed", "total times failed", String(timesFailed)]) + } else { + log("warn", ["index.docker", "too many failed attempts", String(timesFailed), "exiting"]) + Deno.exit(1) + } +}