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

Как проверить, не умерла ли ссылка? - Легкая часть

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

Это довольно ясно и просто. Он вернет истину, если код ответа - 404 (страница не найдена) или ссылка содержит недопустимый домен (UnknownHostException). Во всех остальных случаях будет возвращено false (это не мертвая ссылка). Прежде чем вызвать getResponseCode, я устанавливаю эти 3 параметра:

//parameter #1
connection.setRequestMethod("GET")
//parameter #2
connection.setInstanceFollowRedirects(true)
//parameter #3
connection.setReadTimeout(10000)

Метод запроса (№1) может быть либо GET, либо HEAD. Если для него установлено значение HEAD, то читается только заголовок, поэтому он будет быстрее. В случае GET читается вся страница. Я провел несколько тестов HEAD vs GET на закладках 4K и получил следующие результаты: с HEAD для обработки ссылок потребовалось 34 минуты, а с GET - 47 минут. Это большая разница, и она будет еще больше, если пользователи запустят этот инструмент с 30–40 000 закладок (да, есть некоторые пользователи, у которых столько закладок). Таким образом, HEAD был бы очевидным выбором, но оказалось, что при использовании HEAD несколько закладок были неправильно помечены как мертвые ссылки. По какой-либо причине использование настройки HEAD было ненадежным, поэтому мне пришлось использовать GET.

Не стоит включать функцию Follow Redirect (№2), потому что перенаправления будут выполняться, когда вы откроете ссылку в браузере, и меня интересует состояние «последней» страницы в цепочке.

По поводу тайм-аута (# 3) надо было кое-что решить. Наконец, я установил 10 секунд. Это означает, что если тайм-аут происходит через 10 секунд, я не могу решить, является ли это мертвой ссылкой или нет, поэтому я скорее считаю, что это не мертвая ссылка. Лучше пропустить определение мертвой ссылки, чем пометить закладку как мертвую ссылку, которая на самом деле не является битой ссылкой.

Потом все стало сложнее

Написание метода isLinkDead (см. Выше) было довольно простым делом, но интеграция его в Ninja на уровне качества производства была совсем другим делом. Я провел еще один тест с 40К закладками, и это заняло 27 (!) Часов. Не вопрос, что это действительно долгая операция, поэтому я должен позаботиться о следующем:

  1. Процесс должен выполняться в фоновом режиме (в потоке) на сервере.
  2. Как только пользователь запустил процесс, я должен убедиться, что он не может перезапустить его, пока он запущен.
  3. Когда процесс завершится, пользователь должен получить электронное письмо с уведомлением, в котором будет указано следующее: сколько закладок было проверено, сколько мертвых ссылок было найдено, какой тег использовался для отметки закладок, ссылка на закладки с мертвыми ссылками.
  4. Я должен проверить, какую нагрузку принимает сервер (память, процессор), когда несколько одновременных пользователей запускают FDL (поиск мертвых ссылок), и как эти дополнительные фоновые процессы влияют на повседневное использование Ninja. К счастью, оказалось, что нагрузка настолько минимальна, что в Amazon CloudWatch я буквально не мог даже увидеть лишнюю нагрузку.
  5. Что делать, если необходимо перезапустить сервер или развернуть новую сборку, пока процессы FDL только выполняются? Обработка этого сценария вызвала наибольшие сложности. После перезапуска сервера или развертывания новой сборки мне приходится перезапускать прерванные процессы FDL. Этот механизм тоже нужно было закодировать. Также оказалось, что после развертывания новой сборки потоки, запущенные предыдущим развертыванием, не завершаются (даже если возникают исключения, поскольку старые объекты EJB больше не существуют), они продолжают выполняться. Это странно, потому что после исключения поток должен завершиться. Так что с этим тоже нужно было справиться, старые потоки теперь завершаются вручную.

Урок выучен

Вся история интересна, потому что на кодирование основных функций функции «Поиск мертвых ссылок» ушло примерно 5% или даже меньше всех усилий. Большая часть усилий была направлена ​​на обеспечение хорошего пользовательского опыта на уровне производственного качества. И я даже не упомянул об ошибках (может быть, в другом посте?), Которые я сделал, когда облажался с «концепцией безопасности потоков» или когда я забыл закрыть соединение (connection.disconnect () в приведенном выше коде) во время итерации через тысячи ссылок. Все эти ошибки привели к дополнительным часам отладки. Урок, усвоенный здесь, заключался в том, что не всегда легко оценить усилия, необходимые для разработки новой функции. Лучше оставить больше времени для оценки трудозатрат, даже если на первый взгляд кажется, что эту функцию легко реализовать.