Вот как мое портфолио будит спящие проекты, поэтому мне не нужно платить, чтобы они не спали.

Проблема:

Если вы похожи на меня, у вас есть куча проектов, размещенных на Heroku. Это был очень привлекательный вариант, когда они предлагали бесплатный уровень с 1000 dyno-часов в месяц (после проверки вашей кредитной карты), более чем достаточно, чтобы поддерживать один проект на 100% безотказной работе. Существует множество скриптов, которые посещают ваш проект каждые полчаса или около того, гораздо дольше, и ваши динамометры заснут. Им требуется раздражающие 15–30 секунд, чтобы проснуться от бездействия, проводя все это время в виде очередного сломанного проекта для посетителей, рекрутеров и потенциальных работодателей.

С другой стороны, если вы пытаетесь поддерживать более одного проекта в режиме 24/7, у вас будет в лучшем случае 3 недели безотказной работы, прежде чем у вас закончатся часы динамометра. Когда они заканчиваются, вы можете отобразить пользовательскую страницу ошибки, объясняющую, что происходит, но вы не можете показать работающий проект. Новый эко-уровень Heroku предлагает те же 1000 часов, поэтому, если вы хотите, чтобы несколько приложений работали непрерывно, вам придется заплатить.

Решение:

Стратегия того, как потратить эти драгоценные часы на динамометрическом стенде. Если каждый из ваших проектов будет любезно будить других, когда его посетят, вы можете позволить другим спать, пока один стоит на страже. Это тот, который вы будете настраивать автоматические запросы, чтобы не спать. Выберите, какой проект (надеюсь) получит первое посещение и уже проснулся.

Выделите этот проект в своем портфолио, в своем профиле на LinkedIn, в своем резюме — везде, откуда может зайти потенциальный работодатель. Он должен быть везде одинаковым, потому что он единственный, кто готов справиться с задачей, он единственный, кто все время бодрствует.

Следующий шаг — разбудить их всех.

const autoRun = () => {
  // Gather all your project links...
  const projLinks = document.querySelectorAll('.projLink');
  for (let link of projLinks) {
    // ... And send each one a wakeup request
    fetch(`${link.href}api/wakeup`, {mode: 'no-cors'});
  }
}

autoRun();

Когда этот код запускается после загрузки страницы, он создает массив всех ссылок проекта (в случае моего портфолио, все элементы с классом «projLink») и выполняет итерацию, отправляя запрос GET в /api/wakeup в каждый мой проект. Это не настоящий маршрут API, и он не должен быть таковым. Чтобы серверная часть проверила ее правильность, динамометры должны проснуться и запустить серверную часть, и это буквально все, что нас волнует. Через несколько мгновений после загрузки моего портфолио в браузере потенциального работодателя каждый из моих проектов начинает просыпаться.

У меня есть такой код почти в каждом из моих проектов, хотя это не обязательно ссылки на каждый другой проект для повторения. В таких случаях можно жестко запрограммировать список мест назначения для этих запросов на пробуждение.

Ответ:

Этот fetch на первом этапе генерирует обещание, и когда он получает от сервера ошибку 404, обещание выполняется. Другими словами, скрипт может определить, когда динамометры вашего проекта проснулись. Мы всего лишь пытаемся избежать того, чтобы кто-то смотрел на свой пустой браузер, когда ваш проект просыпается, и думал, что он сломан, но ваш проект сообщает нам, когда он не спит, и мы можем await сделать это.

const autoRun = () => {
  const projLinks = document.querySelectorAll('.projLink');
  for (let link of projLinks) {
    // Listen for clicks on your project links
    link.addEventListener("click", projClickHandler(link.href));
    fetch(`${link.href}api/wakeup`, {mode: 'no-cors'});
  }
}

// Generate a custom click handler for each URL
const projClickHandler = (url) => {
  return async (e) => {
    // Don't just open the page...
    e.preventDefault();
    // ... Show a "Please wait" modal instead ...
    showModal(url);
    const apiUrl = `${url}api/wakeup`;
    // ... And wait for the 404 response ...
    const result = await fetch(apiUrl, {mode: 'no-cors'});
    // ... Before redirecting to the project
    window.location.href = url;
  }
}

const showModal = (url) => {
  // Code to bring up a loading modal, specific to the url of each project
}

autoRun();

Этот await делает здесь всю тяжелую работу. Он приостанавливает выполнение всего вашего синхронного кода и возобновляет его только после того, как обещание, сохраненное как result, будет выполнено (или отклонено) асинхронно.

Исход:

Теперь вы застрахованы от любого посещения чего-либо, что постоянно находится в прямом эфире. Для меня это статичное портфолио, размещенное на страницах Github, плюс один проект на Heroku. Я размещаю эти две ссылки выше во всем — резюме, LinkedIn, Wellfound и т. д. — и надеюсь, что никто не нажмет что-то еще первым.

В наихудшем случае 31-дневный месяц будет стоить 744 динамометрических часа из тысячи, оставив по случайному совпадению 256 часов для других проектов. Это десять с половиной дней, на которые вы могли бы оставить другой проект работающим, но зачем? Теперь у вас есть система.

И паранойя, что кто-то может щелкнуть спящих первым.

Излишнее:

Следующим шагом будет перехват каждого клика по каждому проекту из каждого места. Амбициозный? Точно нет. Уже есть код для выполнения всех сложных задач, все, что ему нужно, — это URL-адрес.

// Save the GET parameters from the URL
const params = new URLSearchParams(window.location.search.toLowerCase());

const autoRun = () => {
  const projLinks = document.querySelectorAll('.projLink');
  for (let link of projLinks) {
    link.addEventListener("click", projClickHandler(link.href));
    fetch(`${link.href}api/wakeup`, {mode: 'no-cors'});
  }

  // Look for a ?modalfor= parameter
  if (params.get('modalfor')) {
    // Save that parameter's value
    const forUrl = params.get('modalfor');
    // Generate a function to launch the modal, using that URL...
    const launcher = projClickHandler(forUrl);
    // Launch the modal, passing in a dummy event object to avoid errors
    launcher({preventDefault: () => {}});
  }
}

const projClickHandler = (url) => {
  return async (e) => {
    e.preventDefault();
    showModal(url);
    const apiUrl = `${url}api/wakeup`;
    const result = await fetch(apiUrl, {mode: 'no-cors'});
    window.location.href = url;
  }
}

const showModal = (url) => { /* ... */ }

autoRun();

Нет причин, по которым URL-адрес должен исходить из ссылки в вашем портфолио, он может взять его из параметра GET, и теперь он может проверить, не активен ли какой-либо веб-сайт, перед перенаправлением на него. Оберните это вокруг ссылок вашего проекта на все, что связано с вашими проектами, и каждый щелчок будет сначала проходить через ваше модальное окно, чтобы показать посетителю что-то преднамеренное, пока вы убедитесь, что оно запущено и работает.

TL; др

Если вы направляете все клики на что-то, что бодрствует 24/7, это единственное, что должно быть бодрствующим 24/7. Затем он может разбудить все остальное и перенаправить только после того, как проснется.

Посмотрите обработчик ссылок в моем портфолио, используя демонстрационный URL-адрес (https://example.test), который не будет перенаправлять, или посетите реальный проект, чтобы увидеть обработчик кликов в действии!

Разработчик

очень хочет услышать от вас, нашли ли вы это полезным, совершенно ужасным, стоящим предложения собеседования или иным образом изменяющим вашу жизнь. Напишите мне на [email protected] и найдите меня в LinkedIn.