Недавно мы столкнулись с ситуацией, когда нам понадобилось создать задание cron присоединять всех из нашей базы данных пользователей находящихся в конце своего триального периода, в базу данных customer.io. Задание cron написать легко, сложно его по уму настроить.
Вариантов несколько:
- можно редактировать /etc/crontab на сервере;
- если используете heroku, то можно сделать это с помощью их планировщика(Scheduler);
- или вы можете использовать реализации cron на предпочтительном вам языке программирования.
Cron задание которое нам было нужно, не было связано с нашим кодом приложения, поэтому не было большого желания держать его на рабочем сервере, а использовать для процесса работающего раз в день и всего 10 секунд, отдельный сервер, кажется несколько расточительно. И вот что мы придумали.
Использовать AWS Lambda/Serverless
AWS Lambda это облачная вычислительная платформа, которая позволяет загрузить какой либо код, и исполнять его в облачном окружении. Прелесть сего метода в том, что платите вы только за время когда ваш код работает(с шагом 100 мс).
В сочетании с АМС ScheduledEvents это стало идеальным решением для нас.
Serverless это фреймворк и утилита командной строки которая упрощает создание функций AWS Lambda через API более удобное, чем официальный модуль узла aws-sdk. Он имеет хорошую документацию для установки, и подробную инструкцию, как дать ему доступ к учетной записи AWS: Инструкция.
Микросервис создается следующими командами (необходимо также установить AWS):
npm i serverless -g
serverless create --template aws-nodejs --path users-ending-trial
cd users-ending-trial
Затем берём файл serverless.yml и добавим опционально время в которое вы намерены выполнять его:
service: users-ending-trial
provider:
name: aws
runtime: nodejs4.3
functions:
fetchTrialUsers:
handler: handler.fetchTrialUsers
events:
# 10am every morning
- schedule: cron(0 10 * * ? *)
Пропишем в handler.js следующее:
'use strict';
const mongo = require('mongodb').MongoClient;
const CUSTOMER_IO_KEY = process.env.CUSTOMER_IO_KEY;
const CUSTOMER_IO_SECRET = process.env.CUSTOMER_IO_SECRET;
const MONGO_READ_URL = process.env.MONGO_READ_URL;
const CustomerIo = require('customerio-node');
const cio = new CustomerIo(CUSTOMER_IO_KEY, CUSTOMER_IO_SECRET);
function getRelativeDate(offset) {
return new Date(new Date().setDate(new Date().getDate() + offset));
}
module.exports.fetchTrialUsers = (event, context, callback) => {
mongo.connect(MONGO_READ_URL, (err, db) => {
db.collection('projects').find({ 'trial.trialEndsAt': { $gt: getRelativeDate(2), $lt: getRelativeDate(4) }, plan: 'free' }).toArray((err, projects) => {
if (err) {
console.error('Error reading projects from database');
return callback(err);
}
Promise.all(projects.map((project) => {
return cio.track(project.owner, { name: 'threeDaysLeft', data: { project } });
})).then(() => {
callback(null, projects.length);
}, (e) => {
console.error('Error tracking customers in customer.io', e);
return callback(e);
});
db.close();
});
});
};
Чтобы тестировать работу локально выполняем:
serverless invoke local -f fetchTrialUsers
Чтобы развернуть в продакшн:
serverless deploy -f fetchTrialUsers
Для запуска используйте ту же команду что и для локального теста, только без local:
serverless invoke -f fetchTrialUsers
И вуаля! Теперь это должно запускать ваш исполняемый код на AWS Lambda каждый день в назначенное время. Этот простой, но очень мощный способ работы, который позволяет сосредоточиться на коде, а не на инфраструктуре, которая требуется для его запуска.
Источник на английском: https://blog.readme.io/