Небольшой проект я начал писать в конце прошлого года и время от времени производил некоторые оптимизации, кратко опишу их здесь.
источник
Прежде чем происхождение не было доступа к проекту узла, работа также ограниченный доступ к узлу сценариев записи, выполняет несколько небольших инструментов, а услуги на сервере под управлением узла. Так что напишите беги на сервере узла небольших проектов практикуют руку.
Мне всегда нравилось использовать RSS для подписки на информацию.Это просто и эффективно.Вместо того, чтобы время от времени получать push-уведомления каждый день и открывать различные веб-приложения для получения информации, лучше взять на себя инициативу и сосредоточиться на их чтении. в то же время. Это позволяет избежать накопления беспокойства от получения информации время от времени каждый день, но часто не могу вспомнить, чтобы открыть ее 😅, после недели открытия Ридера я обнаружил, что накопленная непрочитанная информация снова взорвалась, и это действительно сложно для люди, чтобы быть довольными.
Поэтому я решил сам создать службу доставки информации, чтобы удовлетворить свои основные потребности.Wechat обновляет интерфейсную информацию RSS в 10:00 каждый рабочий день., чтобы вы могли удобно просматривать новые вещи, когда вы приходите на рабочее место каждый день, выбирать несколько полезных и сохранять их для медленного изучения.
Репозиторий проекта:GitHub.com/cola Buddha day you/…
Толчок выглядит так:
Отсканируйте код, чтобы получить push-сервис:
Теперь основными источниками толчка являются колонки Zhihu различных заводов, личные блоги больших парней и популярные статьи о переднем конце Nuggets, все из которых являются моими личными вкусами.
Давайте поговорим о процессе разработки (и добавления требований к себе).
Начинать
Сначала мне кажется, что это требование очень простое, и конкретные операции можно разложить на:
- Напишите файл конфигурации и напишите в нем исходный адрес RSS, который я хочу сканировать.
- Найдите пакет npm, который может анализировать RSS, просматривать источники в файле конфигурации и обрабатывать данные после анализа.
- Отфильтруйте только те статьи, которые были обновлены за последние 24 часа, обработайте данные, объедините их в строку и отправьте через WeChat.
- Сценарий, написанный выше, выполняет запланированное задание, готово!
наконец выбранrss-parserВ качестве инструментария для синтаксического анализаPushBearВ качестве push-сервиса,node-scheduleИнструмент планирования задач записывает версию.
Потом я обнаружил, что моих знаний не хватает, и я не рассматривал проблему защиты процесса при развертывании скрипта на сервере, поэтому я изучил волнуpm2, выполнить задание на отлично.
переход
Написанный здесь проект действительно можно использовать вместе, но он кажется очень низким и неудобным. Основные проблемы:
- В то время существовало около 40 или 50 RSS-каналов, и просмотр и анализ всех каналов за один раз часто приводил к тайм-аутам или ошибкам.
- RSS-канал прописывается в файле конфигурации, каждый раз, когда вы хотите добавить или изменить источник, вам нужно изменить код, который очень низкий.
- PushBearЭтот пуш-сервис может хранить пуши только в течение трех дней, и вы не можете прочитать содержимое пушей трехдневной и недельной давности, что тоже очень неудобно.
- RSS-лент у Наггетс немного, и они не отсортированы по популярности (может, у меня неправильная осанка 😅), что не соответствует требованиям.
Первый пункт немного сложнее, и решение может быть все еще примитивным. Первая проблема заключается в том, что нужно контролировать количество одновременных запросов, а вторая — в том, что сама лента RSS имеет определенную нестабильность. Текущее решение:
- Отделите задачу сканирования от задачи отправки, выделите время для трех циклов сканирования и следующие два раза захватывайте только исходный код, в котором произошел сбой.
- использоватьasyncиз
mapLimit
а такжеtimeout
Метод устанавливает максимальное количество параллелизма и таймаута
Грубый код выглядит следующим образом (есть некоторые детали, которые не были опубликованы):
// 抓取定时器 ID
let fetchInterval = null;
// 抓取次数
let fetchTimes = 0;
function setPushSchedule () {
schedule.scheduleJob('00 30 09 * * *', () => {
// 抓取任务
log.info('rss schedule fetching fire at ' + new Date());
activateFetchTask();
});
schedule.scheduleJob('00 00 10 * * *', () => {
// 发送任务
log.info('rss schedule delivery fire at ' + new Date());
let message = makeUpMessage();
log.info(message);
sendToWeChat(message);
});
}
function activateFetchTask() {
fetchInterval = setInterval(fetchRSSUpdate, 120000);
fetchRSSUpdate();
}
function fetchRSSUpdate() {
fetchTimes++;
if (toFetchList.length && fetchTimes < 4) {
// 若抓取次数少于三次,且仍存在未成功抓取的源
log.info(`第${fetchTimes}次抓取,有 ${toFetchList.length} 篇`);
// 最大并发数为15,超时时间设置为 8000ms
return mapLimit(toFetchList, 15, (source, callback) => {
timeout(parseRSS(source, callback), 8000);
})
}
log.info('fetching is done');
clearInterval(fetchInterval);
return fetchDataCb();
}
Это в основном решает более 90% проблем со сканированием и обеспечивает стабильность скрипта.
Для проблемы с тем, что RSS лента прописана в конфигурационном файле, каждый раз, когда вы хотите добавить или изменить исходник, вам нужно изменить код.Решение очень простое, просто пропишите исходную конфигурацию в MongoDB.Есть некоторый GUI программное обеспечение, которое можно использовать непосредственно в графическом интерфейсе. Добавляйте и изменяйте данные.
Чтобы решить проблему, связанную с тем, что push-сервис может хранить push-уведомления только в течение трех дней, было решено добавить еженедельное задание сканирования каждую пятницу, захват новых статей в течение недели и отправку контента на склад в качестве задачи. Еще решение.
В ответ на проблему с RSS-каналом Nuggets я, наконец, решил напрямую вызывать интерфейс Nuggets для получения данных, чтобы я мог делать все, что захочу, и получать только статьи с более чем 70 лайками ❤️ каждый день.
Кстати, к временному диапазону просканированных статей добавлено значение смещения, чтобы не отфильтровывать статьи хорошего качества, но с меньшим количеством лайков, потому что они только что были опубликованы. Я чувствую себя прекрасно~
function filterArticlesByDateAndCollection () {
const threshold = 70;
// articles 是已按❤️数由高到低排序的文章列表
let results = articles.filter((article) => {
// 偏移值五小时,避免筛掉质量好但是由于刚刚发布点赞较少的文章
return moment(article.createdAt).isAfter(moment(startTime).subtract(5, 'hours'))
&& moment(article.createdAt).isBefore(moment(endTime).subtract(5, 'hours'))
&& article.collectionCount > threshold;
});
// 掘金文章最多收录 8 篇,避免信息爆炸
return results.slice(0, 8);
}
В этот период я также в полной мере ощутил важность лога, и в базу данных была добавлена новая таблица для хранения ежедневного push-контента.
Также вPushBearДобавлен новый канал для отправки логов себе.После выполнения задачи сканирования каждый день, сначала присылайте мне просканированное содержимое.Если я обнаружу какие-либо проблемы, я могу войти на сервер, чтобы срочно починить его (это еще много думать об этом так) низкий 😅).
Обновить
После внесения вышеперечисленных изменений скрипт стабильно работал почти полгода, в этот период я также был занят переноской кирпичей, и у меня не было сил переделывать его снова.
Я не делал никаких акций, но в один прекрасный день я вдруг обнаружил, что на этот сервис подписано более 30 пользователей, поэтому я узнал, что отвечаю за пользователей (и у меня появилась новая технология, которую я хотел попрактиковать 👻 ), так что я сделал это снова Преображение.
Проблемы с проектом на данный момент:
- Нет статьи для дедупликации.Если статья размещена в колонке Zhihu, также размещены Nuggets, а также размещен личный блог автора, это равносильно повторению несколько раз.
- Временной интервал пуша не точен, все отсвечивается за последние 24 часа текущего времени
- Не очень хорошо, чтобы скрипт напрямую подключался к БД для операций доступа, я чувствую, что эта форма сделана в сервер, и разумнее выставить апи во внешний мир (буду использовать его, когда захочу когда-нибудь написать RSS-ридер)
- Каждый раз, когда обновляется код, обновляются зависимости, ssh к серверу, а затем
npm install
Это не кажется очень профессиональным, и есть возможности для улучшения (на самом деле, я хочу использоватьdocker
)
1, 2 Проблема решается легко, перед каждым обходом проверяйте лог и конкретное время последнего нажатия. Каждый раз, когда ловится новая статья, она сравнивается со статьями в логе за последние 7 дней, и дубликаты не включаются в результаты сканирования, и проблема решается.
Что касается вопроса 3, я решил создать сервер Koa, сначала прочитать исходный код push-уведомлений из MongoDB и получить доступ к журналу push-уведомлений в API.
Структура каталогов выглядит следующим образом, добавьтеModel
а такжеController
. Поместите скрипт очистки RSS и сканер слепков в файл задачи.
Нет ничего сложного, вы можете вызвать API для получения RSS-канала:
В этот момент возник важный вопрос,Аутентификация. Определенно невозможно открыть все API по желанию, чтобы внешний мир мог вызывать их произвольно, что эквивалентно раскрытию базы данных.
наконец решил использоватьJSON Web Token(缩写 JWT)
В качестве схемы аутентификации основная причина заключается в том, что JWT подходит для одноразовой краткосрочной аутентификации команды.В настоящее время мой сервис ограничен вызовами API на стороне сервера, а время ежедневного использования невелико, поэтому нет необходимости выпускать токен с длительным сроком действия.
Коа имеет одинjwtпромежуточное ПО
// index.js
app.use(jwtKoa({ secret: config.secretKey }).unless({
path: [/^\/api\/source/, /^\/api\/login/]
}))
После добавления промежуточного ПО, кроме/api/source
а также/api/login
Все интерфейсы должны быть аутентифицированы jwt, прежде чем к ним можно будет получить доступ.
Так напишите/api/login
Интерфейс используется для выдачи токенов, после получения токена установите токен в заголовке запроса для прохождения аутентификации:
// api/base.js
// 用于封装 axios
// http request 拦截器
import axios from 'axios';
const config = require('../config');
const Instance = axios.create({
baseURL: `http://localhost:${config.port}/api`,
timeout: 3000,
headers: {
post: {
'Content-Type': 'application/json',
}
}
});
Instance.interceptors.request.use(
(config) => {
// jwt 验证
const token = config.token;
if (token) {
config.headers['Authorization'] = `Bearer ${token}`
}
return config;
},
error => {
return Promise.reject(error);
}
);
Если в заголовке запроса нет правильного токена, он вернетAuthentication Error
.
Что касается вопроса 4, сервис сейчас относительно прост, и он развернут только на одной машине.Вручную войти на машину и установить npm не составляет большой проблемы.Если машин много и зависимости сложные, то легко вызвать проблемы. Подробнее см.Popular Science: почему npm не устанавливается на сервер?.
Так было решено на основанииDocker
Выполните сборку, развертывание.
FROM daocloud.io/node:8.4.0-onbuild
COPY package*.json ./
RUN npm install -g cnpm --registry=https://registry.npm.taobao.org
RUN cnpm install
RUN echo "Asia/Shanghai" > /etc/timezone
RUN dpkg-reconfigure -f noninteractive tzdata
COPY . .
EXPOSE 3001
CMD [ "npm", "start", "$value1", "$value2", "$value3"]
Он относительно прост в использовании, в основном отвечает за установку зависимостей и запуск служб. Следует отметить два основных момента:
- Вытягивать образы из Китая во внешнюю сеть очень медленно.Я, например, давно тянул официальные образы Node и не стягивал их.В таком случае рекомендуется использовать отечественные образы, такие как Я использую DaoCloud, образы Alibaba Cloud и т. д.
- Поскольку служба push-уведомлений чувствительна ко времени, часовой пояс базового изображения не является местным часовым поясом, поэтому его необходимо установить вручную.
затем перейтиDaoCloudКогда веб-сайты, предоставляющие общедоступные облачные сервисы, авторизованы для доступа к репозиторию Github и подключения к своим собственным хостам, они могут обеспечить непрерывную интеграцию и автоматически создавать и развертывать наши образы. Конкретные шаги см.Построение интерфейсной непрерывной интегрированной среды разработки на основе Docker.
Эта оптимизация, вероятно, заканчивается здесь. Следующее, что нужно сделать, это предоставить страницу просмотра истории push, приоритет не очень высок, сделайте это, когда у вас будет время (кстати, попрактикуйтесь в Nginx).
Текущий план реализации все еще может быть очень неразумным, и предложения приветствуются.