<repo_name>tpohl/callmelater<file_sep>/lib/models/taskSchema.ts
import * as mongoose from 'mongoose';

const Schema = mongoose.Schema;

export const TaskSchema = new Schema({
    url: {
        type: String,
        required: 'Provide an URL'
    },
    payload: {
        type: String,
        required: 'Provide some payload'
    },
    scheduled_date: {
        type: Date,
        required: 'Provide a scheduled date.'
    },
    created_date: {
        type: Date,
        default: Date.now
    },
    retry: {
        type: Number,
        default: 0
    }
});

export const Task = mongoose.model('Task', TaskSchema);<file_sep>/start-callmelater-app.sh
docker stop callmelaterapp
docker rm callmelaterapp
#-p 127.0.0.1:80:80
docker run -d --name callmelaterapp --link callmelaterdb:mongo --restart always  \
    -e "NODE_ENV=production" \
    -e "VIRTUAL_HOST=callmelater.pohl.rocks" -e "PORT=80" \
    -e "LETSENCRYPT_HOST=callmelater.pohl.rocks" -e "LETSENCRYPT_EMAIL=<EMAIL>" \
    -e "MONGODB_URI=mongodb://mongo/tasks" flightsweb<file_sep>/lib/scheduler.ts
import * as cron from "cron";
<file_sep>/Dockerfile
FROM node:8


WORKDIR /home/app


# Install Dependencies
ADD package.json /home/app/package.json

RUN npm install



# Make everything available for start
COPY . /home/app

# Install
RUN npm run build

# Set development environment as default
ENV NODE_ENV production
ENV PORT 80

EXPOSE 80
CMD ["npm", "start"]<file_sep>/lib/routes/taskRoutes.ts
import { Request, Response } from "express";

import { TaskController } from "./taskController";


export class Routes {

    public taskController: TaskController = new TaskController();

    public routes(app): void {

        app.route('/')
            .get((req: Request, res: Response) => {
                res.status(200).send({
                    message: 'GET request successfulll!!!!'
                })
            })

        // Contact 
        app.route('/tasks')
            // GET endpoint 
            .get((req: Request, res: Response) => {
                // Get all contacts            
                res.status(200).send({
                    message: 'GET request successfulll!!!!'
                })
            })
            // POST endpoint
            .post(this.taskController.createTask)
        /*
        .post((req: Request, res: Response) => {   
        // Create new contact         
            res.status(200).send({
                message: 'POST request successfulll!!!!'
            })
        })
        */

        // Contact detail
        app.route('/tasks/:taskId')
            // get specific contact
            .get(this.taskController.getTaskWithID)
            .put(this.taskController.scheduleTask)
            .delete(this.taskController.deleteTask)
    }
}<file_sep>/start-callmelater-db.sh

docker pull mongo
docker stop callmelaterdb
docker rm callmelaterdb
docker run -d -v /root/data/callmelaterdb:/data/db  --name callmelaterdb mongo<file_sep>/lib/app.ts
import * as express from "express";
import * as bodyParser from "body-parser";
import { Routes } from "./routes/taskRoutes";
import * as mongoose from "mongoose";
import * as request from "request-promise-native";
import { CronJob } from "cron";
import { Task } from "./models/taskSchema";

const MONGODB_URI = process.env.MONGODB_URI = process.env.MONGODB_URI || 'mongodb://localhost/taskDb';

const tick = function () {
    console.log('Cron Tick');
    Task.find({})
        .where('scheduled_date').lt(new Date())
        .where('retry').lt(6)
        .exec((err, taskArray) => {
            taskArray.forEach(task => {
                console.log('Found Task', task);
                request({
                    method: 'POST',
                    uri: task.url,
                    body: task.payload,
                    json: false,
                    headers: {
                        'content-type': 'text/plain'
                    }
                }).then((result) => {
                    console.log('Executed Task', task);
                    Task.remove({ _id: task._id }, (err, t2) => {
                        if (err) {
                            console.error('Could not delete task', task)
                        }

                    });
                }, err => {
                    console.error('Cannot Execute Task', err, task);
                    task.retry = task.retry ? (task.retry + 1) : 1;
                    Task.findOneAndUpdate({ _id: task._id }, task, { new: true }, (err, tasknew) => {
                        if (err) {
                            console.error('Adding retry failed', err, task);
                        }
                        else {
                            console.log('Updated retry for task', tasknew.retry, task.retry, task._id);
                        }
                    });
                });
        });
});
}

class App {

    public app: express.Application;
    public routePrv: Routes = new Routes();
    public mongoUrl: string = MONGODB_URI;

    private cron;

    constructor() {
        this.app = express();
        this.config();
        this.routePrv.routes(this.app);
        this.mongoSetup();
        tick();
    }

    private config(): void {
        this.app.use(bodyParser.json());
        this.app.use(bodyParser.urlencoded({ extended: false }));
        // Schedule the Cron
        this.cron = new CronJob(`*/5 * * * *`, tick).start();
    }


    private mongoSetup(): void {
        mongoose.Promise = global.Promise;
        mongoose.connect(this.mongoUrl);
    }

}

export default new App().app;<file_sep>/lib/routes/taskController.ts

import { Task } from '../models/taskSchema';
import { Request, Response } from 'express';


export class TaskController {

    public createTask(req: Request, res: Response) {
        let newTask = new Task(req.body);

        newTask.save((err, task) => {
            if (err) {
                res.send(err);
            }
            console.log('Scheduled Task', task);
            res.json(task);
        });
    }

    public getAllTasks(req: Request, res: Response) {
        Task.find({}, (err, task) => {
            if (err) {
                res.send(err);
            }
            res.json(task);
        });
    }

    public getTaskWithID(req: Request, res: Response) {
        Task.findById(req.params.taskId, (err, contact) => {
            if (err) {
                res.send(err);
            }
            res.json(contact);
        });
    }

    public scheduleTask(req: Request, res: Response) {
        Task.findOneAndUpdate({ _id: req.params.taskId }, req.body, { new: true }, (err, contact) => {
            if (err) {
                res.send(err);
            }
            res.json(contact);
        });
    }

    public deleteTask(req: Request, res: Response) {
        Task.remove({ _id: req.params.taskId }, (err, contact) => {
            if (err) {
                res.send(err);
            }
            res.json({ message: 'Successfully deleted Task!' });
        });
    }
}
<file_sep>/build.sh
docker build -t callmelaterapp .