1 апреля близко-близко
И сердце бьётся как олень
Не подведи меня... а, это про другой день же!
Что ж, весна приносит не только слякоть и долгожданное солнышко, но и некоторые сетевые проблемы, коих в ближайшей перспективе, может только прибавиться.
Поэтому - на всякий случай - оставляю, альтернативные точки связи:
- сделал cообщество https://vk.ru/ordo_code;
- и там же канал https://vk.ru/im/channels/-236655784;
Как этим всем управлять и что там вообще можно делать - я пока представляю смутно.
Для меня ВК всегда был чем-то непонятным, и, честно говоря, таким он и остался. Но реалии требуют адаптироваться - попробую с ним как-то подружиться.
Тут всё довольно привычно и максимально тележно.
У адептов социального эксгибиционизма, может случится приступ переживания за приватность, но мне переживать не за что.
В общем, присоединяйтесь!
Будем на связи, в это непростое сепаратное время.
#на_связи
Please open Telegram to view this post
VIEW IN TELEGRAM
👀1
Даже в Laravel не обойтись без политики
— Как проверить права доступа к модели через Policy —
Сегодня хочу поговорить о политике.
Чего я хуже остальных, что ли...✊
TL;DR
Возникла задача добавить проверку при удаления файла - разрешить пользователю удалять только свои собственные файлы.
Самый простой и правильный способ сделать это в Laravel - использовать Policy.
Policy - специальные классы в Laravel, позволяющие определить логику авторизации для конкретной модели или ресурса.
Преимущества подхода с политиками:
Централизация логики доступа
Поведение задаётся в одном месте - в классе политики
Переиспользование
Policy можно использовать в разных частях приложения
В контроллере:
В шаблонах:
В маршрутах:
Улучшение читаемости
более очевидно считывается, чем
Масштабируемость
Логика доступа со временем может усложняться (роли, админы, shared-ресурсы и т.д.), но благодаря централизованному описанию политики изменения вносятся в одном месте.
Расширяемость
Можно добавлять собственные методы политик, а не ограничиваться только стандартными.
Тестируемость
Отдельный метод политики легко покрывается тестами.
Чёткое разделение ответственности
—
—
—
Policy обнаруживаются автоматически в проекте, если структура проекта стандартная:
Laravel автоматически сопоставит:
Никакой регистрации не требуется.
(Но при необходимости политику можно зарегистрировать вручную в
—————
Политики создаются командой:
А дальше происходит магия соглашения именования и политика применяется к модели.✨
Для своего случая я выбрал вариант проверки доступности на уровне обработки маршрута:
В итоге получается аккуратное, архитектурно правильное и читаемое решение.
Если файл принадлежит пользователю - удаляем, а нет - извините, политика. 📄
#laravel #policy #authorize #backend #web #разработка
— Как проверить права доступа к модели через Policy —
Сегодня хочу поговорить о политике.
Чего я хуже остальных, что ли...
TL;DR
Проверку доступа к модели удобно выносить в Policy и подключать в карте маршрутов.
Возникла задача добавить проверку при удаления файла - разрешить пользователю удалять только свои собственные файлы.
Самый простой и правильный способ сделать это в Laravel - использовать Policy.
Policy - специальные классы в Laravel, позволяющие определить логику авторизации для конкретной модели или ресурса.
Преимущества подхода с политиками:
Централизация логики доступа
Поведение задаётся в одном месте - в классе политики
public function delete(User $user, Attachment $attachment)
{
return $attachment->user_id === $user->id;
}
Переиспользование
Policy можно использовать в разных частях приложения
В контроллере:
$this->authorize('delete', $attachment);В шаблонах:
@can('delete', $attachment)
<button>Delete</button>
@endcanВ маршрутах:
->can('delete', 'attachment')Улучшение читаемости
$this->authorize('delete', $attachment);более очевидно считывается, чем
if ($attachment->user_id !== auth()->id())
Масштабируемость
Логика доступа со временем может усложняться (роли, админы, shared-ресурсы и т.д.), но благодаря централизованному описанию политики изменения вносятся в одном месте.
Расширяемость
Можно добавлять собственные методы политик, а не ограничиваться только стандартными.
Тестируемость
Отдельный метод политики легко покрывается тестами.
Чёткое разделение ответственности
—
Controller - обрабатывает запрос;—
Policy - определяет доступ;—
Model - определяет данные;Policy обнаруживаются автоматически в проекте, если структура проекта стандартная:
app/
├─ Models/
│ └─ Attachment.php
└─ Policies/
└─ AttachmentPolicy.php
Laravel автоматически сопоставит:
Attachment → AttachmentPolicy
Никакой регистрации не требуется.
(Но при необходимости политику можно зарегистрировать вручную в
AppServiceProvider.)—————
Политики создаются командой:
php artisan make:policy AttachmentPolicy --model=Attachment
А дальше происходит магия соглашения именования и политика применяется к модели.
Для своего случая я выбрал вариант проверки доступности на уровне обработки маршрута:
Route::post('/upload/{attachment}/delete', [UploadController::class, 'delete'])
->can('delete', 'attachment')
->name('upload.remove');В итоге получается аккуратное, архитектурно правильное и читаемое решение.
Если файл принадлежит пользователю - удаляем, а нет - извините, политика. 📄
#laravel #policy #authorize #backend #web #разработка
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2❤1
Читальня. Питер В. Бретт – Дневная битва
— Такова инэвера —
Продолжаем погружаться в мир Тесы и противостояние людей идемонов людей в третьей книге.
Историяпродолжается начинается заново, но теперь с детства Инэверы - лет за 30 до основных событий, когда могущественная Дамаджах была девочкой и помогала матери плести корзинки.
Если в Копье пустыни нам рассказывали о ханну паш мальчиков, то теперь нам показывают путь девочек - от босячек до загадочных и всемогущих дама'тинг - это если повезёт. Как оказалось, нравы в женских казармах ничуть не мягче чем в мужских - та же жестокость и вечная борьба за место под солнцем.
В остальном, перед нами большое количество политики: придворные игры, интриги, манипуляции и борьба за власть. Красийцы, в лице Джардира, строят планы позавоеванию объединению всё ещё разрозненных поселений северян. 👑
И тут неожиданно интересен Аббан - хаффит, торгаш и поедатель свинины - вообще, на мой взгляд, один из самых любопытных персонажей книги. Пока все вокруг спасают мир, ведут священные войны и исполняют пророчества, Аббан просто делает бизнес.
Герои прокачивают свои магические навыки: Ренна, Арлен, Рожер и даже Лиша, со своим почти научным подходом к делу магии - у всех появляются новые перки. Люди активно совершенствуют оружие и доспехи, покрывая всё - от кончиков пальцев до острия копья - защитными и атакующими метками. Все готовятся к очередному пришествию демонической орды.
Рожер, кстати, прокачался не только в магии: он взял лучшее из красийских традиций - окружил себя двойной красотой. Причём, если с демонами он справляется довольно уверенно, то в домашней дипломатии всё заметно сложнее и запутанее.🚹
Да, совсем уж про демонов автор не забывает. Битва с демонами будет - и демонов на новолуние завезут в изрядных количествах. Они даже будут совершить разные непотребства с главными героями. И в какой-то момент мечта Джардира - объединить людей в битве против демонов - на какое-то время сбудется.
Итого: хорошее продолжение истории. На мой взгляд, немного слабее предыдущих книг, но в целом планку держит на высоте.
Хотя, если честно, создаётся ощущение, что без этой части история в глобальном смысле не слишком много бы потеряла.
7 хора из 10🎲
#книги #почитать #ПитерВБретт #Бретт #ВселеннаяМеченого #ДневняБитва #тёмное #фентези #магия #монстры
— Обзор первой книги - Меченый
— Обзор второй книги - Копьё пустыни
— Обзор четвёртой книги - Трон Черепов
— Такова инэвера —
Продолжаем погружаться в мир Тесы и противостояние людей и
История
Если в Копье пустыни нам рассказывали о ханну паш мальчиков, то теперь нам показывают путь девочек - от босячек до загадочных и всемогущих дама'тинг - это если повезёт. Как оказалось, нравы в женских казармах ничуть не мягче чем в мужских - та же жестокость и вечная борьба за место под солнцем.
В остальном, перед нами большое количество политики: придворные игры, интриги, манипуляции и борьба за власть. Красийцы, в лице Джардира, строят планы по
И тут неожиданно интересен Аббан - хаффит, торгаш и поедатель свинины - вообще, на мой взгляд, один из самых любопытных персонажей книги. Пока все вокруг спасают мир, ведут священные войны и исполняют пророчества, Аббан просто делает бизнес.
Герои прокачивают свои магические навыки: Ренна, Арлен, Рожер и даже Лиша, со своим почти научным подходом к делу магии - у всех появляются новые перки. Люди активно совершенствуют оружие и доспехи, покрывая всё - от кончиков пальцев до острия копья - защитными и атакующими метками. Все готовятся к очередному пришествию демонической орды.
Рожер, кстати, прокачался не только в магии: он взял лучшее из красийских традиций - окружил себя двойной красотой. Причём, если с демонами он справляется довольно уверенно, то в домашней дипломатии всё заметно сложнее и запутанее.
Да, совсем уж про демонов автор не забывает. Битва с демонами будет - и демонов на новолуние завезут в изрядных количествах. Они даже будут совершить разные непотребства с главными героями. И в какой-то момент мечта Джардира - объединить людей в битве против демонов - на какое-то время сбудется.
Итого: хорошее продолжение истории. На мой взгляд, немного слабее предыдущих книг, но в целом планку держит на высоте.
Хотя, если честно, создаётся ощущение, что без этой части история в глобальном смысле не слишком много бы потеряла.
7 хора из 10
#книги #почитать #ПитерВБретт #Бретт #ВселеннаяМеченого #ДневняБитва #тёмное #фентези #магия #монстры
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Не каналами едиными
- Динамическое логирование через Monolog без config/logging.php -
Что ж, поговорим о логировании.
TL;DR
Laravel под капотом имеет удобную систему логирования на основе библиотеки Monolog и каналов логирования. В большинстве случаев этого более чем достаточно, но бывают и исключения, когда каналы начинают мешать.
Мне необходимо было генерировать собственные логи под определённую рутину.✍️
Что за рутина? Микросервис по рассылке автоматических push-уведомлений.
Микросервис на основе генераторов формирует и отправляет пользователям push-уведомления. При этом необходимо логировать процесс генерации: логика довольно ветвистая, сценариев много, а потому нужен глаз да глаз.
Загвоздка заключалась в том, что генераторы создаются автоматически через UI, а поэтому заранее предугадать список каналов логирования невозможно - а логировать надо. Можно было бы всё писать в один файл... да поди потом разберись в мегабайтах текста что там вообще происходит.😰
Не долго кручинясь и не сильно вешая буйну голову, накидал небольшой сервис логирования, который работает без заранее прописанных каналов:💡
RotatingFileHandler автоматически создаёт ежедневные файлы логов:
Ну а дальше всё просто:
В итоге каждый генератор может писать в свой собственный лог, не требуя объявления каналов в config/logging.php.
Иногда лучший способ использовать Laravel - это перестать использовать Laravel.😏
#laravel #logging #monolog #backend #web #разработка
- Динамическое логирование через Monolog без config/logging.php -
Что ж, поговорим о логировании.
TL;DR
Если каналы Laravel не подходят - используем Monolog напрямую. RotatingFileHandler, маленький сервис - и каждый генератор пишет в свой лог.
Laravel под капотом имеет удобную систему логирования на основе библиотеки Monolog и каналов логирования. В большинстве случаев этого более чем достаточно, но бывают и исключения, когда каналы начинают мешать.
Мне необходимо было генерировать собственные логи под определённую рутину.
Что за рутина? Микросервис по рассылке автоматических push-уведомлений.
Микросервис на основе генераторов формирует и отправляет пользователям push-уведомления. При этом необходимо логировать процесс генерации: логика довольно ветвистая, сценариев много, а потому нужен глаз да глаз.
Загвоздка заключалась в том, что генераторы создаются автоматически через UI, а поэтому заранее предугадать список каналов логирования невозможно - а логировать надо. Можно было бы всё писать в один файл... да поди потом разберись в мегабайтах текста что там вообще происходит.
Не долго кручинясь и не сильно вешая буйну голову, накидал небольшой сервис логирования, который работает без заранее прописанных каналов:
class LoggerService
{
protected Logger $logger;
public function __construct(string $filename = 'custom.log')
{
$this->logger = new Logger('custom');
$this->logger->pushHandler(
new RotatingFileHandler(
storage_path('logs/' . $filename),
14,
Logger::DEBUG
)
);
}
....
}
RotatingFileHandler автоматически создаёт ежедневные файлы логов:
storage/logs/push-generator-1-2026-04-07.log
storage/logs/push-generator-1-2026-04-08.log
Ну а дальше всё просто:
$logger = new LoggerService('push-generator-1.log');
$logger->info('Начало генерации');
$logger->warning('Устройство пропущено', ['device_id' => 42]);
$logger->error('Ошибка отправки', ['token' => $token]);В итоге каждый генератор может писать в свой собственный лог, не требуя объявления каналов в config/logging.php.
Иногда лучший способ использовать Laravel - это перестать использовать Laravel.
#laravel #logging #monolog #backend #web #разработка
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Как я перестал бояться SQL... и создал полезного монстра
— Как один SQL заменил пачку запросов и килограммы PHP —
Ох, маркетинг, такой маркетинг!
TL;DR
Есть задача: вернуть пользователя к просмотру сериала, который он недосмотрел, и отправить ему push с призывом продолжить.🍿
Изи-пизи... если бы не ряд условий:
- надо найти пользователей, которые смотрели хоть что-то;
- при этом отсеять тех, кто уже досмотрел сериал;
- выбрать “приоритетный” сериал:
— сначала по дате последнего просмотра;
— если одинаково - по количеству просмотренных эпизодов;
Решая задачу «в лоб», на горизонте замаячило большое количество запросов к БД, обработка данных на стороне бэкенда, забитая память и прочие радости. В общем, в перспективе запахло это всё не очень, и я начал терять волю.🤨
А ещё это ломало мою выстроенную парадигму:
Так как требовало дополнительной реализации обработчика, а я человек ленивый.🙄
Вспомнив своё банковское прошлое (ммм, какие там делали причудливые запросы к БД) решил попробовать утащить всю логику в SQL.
В итоге решение можно представить в виде такой схемы:💡
Не совсем тривиальный SELECT, да?😄
Весь SQL приводить не буду - он разросся строк до ~70 и слегка пугает неподготовленного зрителя, но, в целом, картина примерно такая:
Да, выглядит немного монструозно, но результат - просто конфетка.❤️
Что тут интересного:
- использую цепочку CTE (Common Table Expression) через WITH для подготовки данных;
- считаю просмотры и отдельно количество эпизодов;
- отсекаю полностью просмотренные сериалы прямо в БД;
- ранжирую сериалы внутри каждого пользователя через оконные функции (ROW_NUMBER);
- собираю результат в JSON (JSON_OBJECT), чтобы не городить DTO на бэкенде;
⚠️ Но WITH не всегда бесплатно. Иногда MySQL может материализовать CTE и положить данные физически на диск, поэтому в тяжёлых запросах не забываем про EXPLAIN.
It's alive! It's alive!
#sql #cte #with #backend #разработка
— Как один SQL заменил пачку запросов и килограммы PHP —
Ох, маркетинг, такой маркетинг!
TL;DR
Собрал сегмент “недосмотренных сериалов” одним SQL-запросом через WITH + оконные функции. Убрал N+1, сократил нагрузку на бэкенд и получил готовые данные под пуши прямо из БД.
Есть задача: вернуть пользователя к просмотру сериала, который он недосмотрел, и отправить ему push с призывом продолжить.
Изи-пизи... если бы не ряд условий:
- надо найти пользователей, которые смотрели хоть что-то;
- при этом отсеять тех, кто уже досмотрел сериал;
- выбрать “приоритетный” сериал:
— сначала по дате последнего просмотра;
— если одинаково - по количеству просмотренных эпизодов;
Решая задачу «в лоб», на горизонте замаячило большое количество запросов к БД, обработка данных на стороне бэкенда, забитая память и прочие радости. В общем, в перспективе запахло это всё не очень, и я начал терять волю.
А ещё это ломало мою выстроенную парадигму:
запрос к БД -> получение данных -> подготовка данных -> отправка сообщения. Так как требовало дополнительной реализации обработчика, а я человек ленивый.
Вспомнив своё банковское прошлое (ммм, какие там делали причудливые запросы к БД) решил попробовать утащить всю логику в SQL.
В итоге решение можно представить в виде такой схемы:
view_histories (история просмотров)
↓
series_stats (агрегация)
↓
episodes_total (общее число эпизодов)
↓
filtered_series (отсекаем досмотренные)
↓
ranked_series (ранжирование)
↓
финальный SELECT
Не совсем тривиальный SELECT, да?
Весь SQL приводить не буду - он разросся строк до ~70 и слегка пугает неподготовленного зрителя, но, в целом, картина примерно такая:
WITH series_stats AS (
...
),
episodes_total AS (
...
),
filtered_series AS (
SELECT
ss.*,
et.total_episodes
FROM series_stats ss
INNER JOIN episodes_total AS et
ON et.content_id = ss.content_id
WHERE ss.watched_episodes < et.total_episodes
),
ranked_series AS (
SELECT
fs.*,
ROW_NUMBER() OVER (
PARTITION BY fs.app_user_id
ORDER BY fs.last_viewed_at DESC, fs.watched_episodes DESC, fs.content_id DESC
) AS rn
FROM filtered_series AS fs
)
SELECT DISTINCT
...
JSON_OBJECT(
'content_id', rs.content_id,
'watched_episodes', rs.watched_episodes,
'total_episodes', rs.total_episodes,
'last_viewed_at', rs.last_viewed_at
) AS params
FROM app_users AS au
...
INNER JOIN ranked_series rs
ON rs.app_user_id = au.id
AND rs.rn = 1
...
Да, выглядит немного монструозно, но результат - просто конфетка.
Что тут интересного:
- использую цепочку CTE (Common Table Expression) через WITH для подготовки данных;
- считаю просмотры и отдельно количество эпизодов;
- отсекаю полностью просмотренные сериалы прямо в БД;
- ранжирую сериалы внутри каждого пользователя через оконные функции (ROW_NUMBER);
- собираю результат в JSON (JSON_OBJECT), чтобы не городить DTO на бэкенде;
It's alive! It's alive!
#sql #cte #with #backend #разработка
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Читальня. Д. Кюнскен – Квантовый сад
— "Срань Господня!" - крикнул Стилс. - "Он антиматерией стреляет!" —
На манеже всё те же — Белизариус Архона снова тащит нас в квантовую шизофрению. Перед нами прямое продолжение немного неоднозначного, но всё-таки весьма интересного «Квантового волшебника».
Мы оказываемся ровно там, где закончилась история первой части: Белизариус всех объегорил, умыкнул врата времени у Суб-Сахарского Союза и нашёл свою асисяй. И тут бы жить-поживать, да добра наживать, но суровая жопа реальности находит нашего героя в виде Конгрегации.
Тут Белизариус рефлексирует.
Конгрегация задумывается о возможностях Homo quantus и в итоге начинают видеть угрозу в квантовых людях. Дабы пресечь угрозу на корню - решают проблему основательно и геноцидят весь родной род Архоны.
Тут Белизариус снова рефлексирует.
Основные действия книги происходят 39 лет назад - да, ребята воспользовались вратами времени, и полетели в прошлое, в те времена, когда Суб-Сахарский Союз был молодым и неокрепшим. Члены экспедиции спали в плохо отапливаемых казармах, над головой висел коричневый карлик, обещая вот-вот погаснуть, а сама экспедиция погрязла в политических интригах и расприях.
На этом фоне появляются двое из ларца: Белизариус и Иеканджика - их задача не наломать дров в прошлом, дабы будущее осталось нетронутым. Решая задачу временных парадоксов, герои оказываются втянутыми в шпионские страсти, с весьма драматичным финалом.
В казармах Белизариус тоже рефлексирует.
Но самое интересное, что герои находят необычную квантовую форму жизни - растения, чей жизненный цикл основан на принципах квантовой суперпозиции. У неё даже есть свой язык, основанный на запахах, и учёные суб-сахарского союза создали девайс-переводчик для общения с ними. Но в итоге судьбу Hortus quantus решает интерпретация фон Неймана — Вигнера (даже пришлось подсмотреть что это такое).💡
Над растениями пуще прежнего рефлексирует Белизариус.
Ещё я бы отметил один момент - это преобразование в Пугало - универсального солдата Конгрегации. И хотя всю книгу сей персонаж сидит в замкнутом пространстве и, в целом не сильно отсвечивает, но история его становления и преобразования кажется неплохой разбавкой общему тону книги. Да и вообще, развить бы историю персонажа - отличный был бы антогонист.
И тут... Ха! Нет! Тут Белизариус не рефлексирует!😄
Итого: книга ощутимо слабее Квантового волшебника - душевных переживаний слишком много, описаний 22-х мерного пространства хватило ещё в первой книге, а сюжет какой-то невзрачный по итогу. И знаете... возглас Стилса очень хорошо описывает послевкусие от книги. Не-не, я не про антиматерию ;)
Но при всём при этом, если у нас издадут продолжение, я скорее всего его почитаю💅 (говорят там подинамичнее происходящее) - вселенная же ж интересная, а геномодифицированные люди до конца себя ещё не показали.
5 пугало из 10
#книги #почитать #ДерекКюнскен #Кюнскен #КвантоваяЭволюция #КвантовыйСад #хроно #фантастика #космос
— Обзор первой книги - Квантовый волшебник
— "Срань Господня!" - крикнул Стилс. - "Он антиматерией стреляет!" —
На манеже всё те же — Белизариус Архона снова тащит нас в квантовую шизофрению. Перед нами прямое продолжение немного неоднозначного, но всё-таки весьма интересного «Квантового волшебника».
Мы оказываемся ровно там, где закончилась история первой части: Белизариус всех объегорил, умыкнул врата времени у Суб-Сахарского Союза и нашёл свою асисяй. И тут бы жить-поживать, да добра наживать, но суровая жопа реальности находит нашего героя в виде Конгрегации.
Тут Белизариус рефлексирует.
Конгрегация задумывается о возможностях Homo quantus и в итоге начинают видеть угрозу в квантовых людях. Дабы пресечь угрозу на корню - решают проблему основательно и геноцидят весь родной род Архоны.
Тут Белизариус снова рефлексирует.
Основные действия книги происходят 39 лет назад - да, ребята воспользовались вратами времени, и полетели в прошлое, в те времена, когда Суб-Сахарский Союз был молодым и неокрепшим. Члены экспедиции спали в плохо отапливаемых казармах, над головой висел коричневый карлик, обещая вот-вот погаснуть, а сама экспедиция погрязла в политических интригах и расприях.
На этом фоне появляются двое из ларца: Белизариус и Иеканджика - их задача не наломать дров в прошлом, дабы будущее осталось нетронутым. Решая задачу временных парадоксов, герои оказываются втянутыми в шпионские страсти, с весьма драматичным финалом.
В казармах Белизариус тоже рефлексирует.
Но самое интересное, что герои находят необычную квантовую форму жизни - растения, чей жизненный цикл основан на принципах квантовой суперпозиции. У неё даже есть свой язык, основанный на запахах, и учёные суб-сахарского союза создали девайс-переводчик для общения с ними. Но в итоге судьбу Hortus quantus решает интерпретация фон Неймана — Вигнера (даже пришлось подсмотреть что это такое).
Над растениями пуще прежнего рефлексирует Белизариус.
Ещё я бы отметил один момент - это преобразование в Пугало - универсального солдата Конгрегации. И хотя всю книгу сей персонаж сидит в замкнутом пространстве и, в целом не сильно отсвечивает, но история его становления и преобразования кажется неплохой разбавкой общему тону книги. Да и вообще, развить бы историю персонажа - отличный был бы антогонист.
И тут... Ха! Нет! Тут Белизариус не рефлексирует!
Итого: книга ощутимо слабее Квантового волшебника - душевных переживаний слишком много, описаний 22-х мерного пространства хватило ещё в первой книге, а сюжет какой-то невзрачный по итогу. И знаете... возглас Стилса очень хорошо описывает послевкусие от книги. Не-не, я не про антиматерию ;)
Но при всём при этом, если у нас издадут продолжение, я скорее всего его почитаю
5 пугало из 10
#книги #почитать #ДерекКюнскен #Кюнскен #КвантоваяЭволюция #КвантовыйСад #хроно #фантастика #космос
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥1
Призраки в сети — тайна пропадающего домена
— О чём молчат минималистичные Docker-образы —
TL;DR
Интересный кейс случился на днях. В логах приложения стали сыпаться сообщения:
🤌
Первым делом проверил что там видит
Оказалось - нифига он не видит.
Проверил что видит сам хост:
Видит! Видит таймаут.🤦♂️
Пропинговал DNS-сервер, которые выдал провайдер - не пингуется.
На всякий случай проверил резолв на общеизвестных DNS-серверах:
И получил вполне бодрый ответ - домен резолвится отлично.
Сделав единственно логичный вывод, - проблема на стороне хостера с DNS-сервером - приступил к лечению:
— отредачил
— обновил DNS на интерфейсе
— прописал адреса DNS для docker пожёстче:
Отписал в поддержку о проблеме и пошёл пить кофе, и жевать конфеты!☕️
В безмятежном состоянии пребывал не долго - повальная ошибка😭
Картина получалась интересная: на хосте домен резолвился без каких-либо замечаний, а вот из докера домен периодически не резолвился - то есть DNS то жив, то мёртв, то притворяется.
И вот тут я реально приуныл, потому что никаких явных причин для такого поведения просто не было.
Пробовалось многое:
— перевод запросов к DNS на tcp;
— разумеется, несколько ребутов;
— пересоздание сетей
— молитвы Омниссии🤖 ;
В общем, весь опыт накопленный человечеством оказался бесполезен.😡
Дабы долго не томить - проблема оказалась в образе -
Известные проблемы
— упрощённый DNS‑клиент.
— ограниченная обработка ошибок. При проблемах с первым DNS‑сервером
— особенности кэширования. Поведение кэша DNS в
— сетевые взаимодействия. В Docker‑сетях (особенно overlay)
— таймауты.
❗️ Мораль❗️
Ну, а
Моё сердце разбито!😭
#docker #php #laravel #alpine #musl #devops #backend #web #разработка
— О чём молчат минималистичные Docker-образы —
TL;DR
Если Docker-контейнер на php:*-alpine периодически ловит cURL error 6: Could not resolve host, - проблема может быть в musl, а не в Docker или DNS.
Интересный кейс случился на днях. В логах приложения стали сыпаться сообщения:
cURL error 6: Could not resolve host: here-some-secret-domain.com
Первым делом проверил что там видит
docker у себя внутрях при резолве домена:docker compose exec php getent hosts here-some-secret-domain.com
Оказалось - нифига он не видит.
Проверил что видит сам хост:
dig here-some-secret-domain.com
;; communications error to 172.16.2.231#53: timed out
Видит! Видит таймаут.
Пропинговал DNS-сервер, которые выдал провайдер - не пингуется.
На всякий случай проверил резолв на общеизвестных DNS-серверах:
dig @8.8.8.8 here-some-secret-domain.com
; <<>> DiG 9.10.6 <<>> @8.8.8.8 here-some-secret-domain.com
; (1 server found)
И получил вполне бодрый ответ - домен резолвится отлично.
Сделав единственно логичный вывод, - проблема на стороне хостера с DNS-сервером - приступил к лечению:
— отредачил
/etc/resolv.conf, указав, что используем 8.8.8.8 и 4.4.4.4;— обновил DNS на интерфейсе
resolvectl dns eth0 4.4.4.4 8.8.8.8;— прописал адреса DNS для docker пожёстче:
services:
php:
dns:
- 8.8.8.8
- 4.4.4.4
Отписал в поддержку о проблеме и пошёл пить кофе, и жевать конфеты!
В безмятежном состоянии пребывал не долго - повальная ошибка
cURL error 6: Could not resolve host ушла, но периодически нет-нет, да и появится. И это было весьма болезнено. Картина получалась интересная: на хосте домен резолвился без каких-либо замечаний, а вот из докера домен периодически не резолвился - то есть DNS то жив, то мёртв, то притворяется.
И вот тут я реально приуныл, потому что никаких явных причин для такого поведения просто не было.
Пробовалось многое:
— перевод запросов к DNS на tcp;
— разумеется, несколько ребутов;
— пересоздание сетей
docker;— молитвы Омниссии
В общем, весь опыт накопленный человечеством оказался бесполезен.
Дабы долго не томить - проблема оказалась в образе -
php:8.4-fpm-alpine. Alpine использует musl вместо glibc, и у musl исторически бывают очень нестабильные отношения с DNS, Docker networking и резолверами.Известные проблемы
musl с DNS:— упрощённый DNS‑клиент.
musl не реализует все механизмы glibc, например, сложные стратегии ретраев и таймаутов;— ограниченная обработка ошибок. При проблемах с первым DNS‑сервером
musl может не переключиться на следующий в списке;— особенности кэширования. Поведение кэша DNS в
musl отличается от glibc - возможны устаревшие ответы или пропуски обновлений;— сетевые взаимодействия. В Docker‑сетях (особенно overlay)
musl иногда некорректно обрабатывает ответы от встроенного DNS‑сервера Docker (127.0.0.11).— таймауты.
musl имеет жёсткие таймауты по умолчанию, что критично при задержках в сети;Не гонись, поп, за дешевизной -
Малый образ - геморрой длиной в полжизни!
Ну, а
alpine теперь буду использовать только для локальной разработки, а ведь образы так нравились своей минималистичностью. Моё сердце разбито!
#docker #php #laravel #alpine #musl #devops #backend #web #разработка
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Хирургическая очистка кэша в Yii2
— Не все зависимости одинаково вредны —
TL;DR
Что ж друзья, сегодня поговорим о зависимостях. Все знают, что это такое. Сначала кажется, что всё под контролем. Потом они начинают влиять на твою жизнь. А потом ты уже не представляешь, как жил без них.😍
Зависимости бывают у всех. У людей, у проектов, у
Кароч! Рассказываю...
Делал я одну фичу. Суть её сейчас не важна, но появилась необходимость складывать данные, получаемые в ходе работы, в кэш. Ну надо так надо - складываем. А что делают с кэшированными данными? Правильно — периодически чистят для поддержания гигиены и актуальности. И вот тут нашла коса на камень.
Ключи кэша в данной фиче составные и зависят от ряда параметров. Ключи примерно такие —😫
И как это всё очищать спросите вы. Ведь спросите же?
Вариантов решения вроде бы хватает. Можно хранить список ключей отдельно, можно искать по префиксам, можно генерировать какие-нибудь служебные ключи для очистки, но всё это выглядит как костыли. Не, можно ещё беспощадно сделать —
Другое дело — зависимости кэша.💡
Для своей задачи я использовал:
Синтаксис максимально простой и понятный:
А инвалидация кэша делается ещё проще:
Разумеется, работает это только с кэш-бэкендами, которые поддерживают зависимости, но для типичных Redis, Memcached и файлового кэша проблем обычно не возникает.
И всё — никаких тебе поисков по префиксам, генерации ключей и прочего мракобесия.
Просто, изящно, профессионально!☕️
#php #yii2 #cache #dependency #backend #web #разработка
— Не все зависимости одинаково вредны —
TL;DR
Волшебный TagDependency позволяет привязать к одному тегу сколько угодно записей кэша и потом инвалидировать их одной командой.
Что ж друзья, сегодня поговорим о зависимостях. Все знают, что это такое. Сначала кажется, что всё под контролем. Потом они начинают влиять на твою жизнь. А потом ты уже не представляешь, как жил без них.
Зависимости бывают у всех. У людей, у проектов, у
npm-пакетов... и даже у кэша в Yii2. И штука эта, надо сказать, офигенная, хотя пользуются ей незаслуженно редко. За всю свою практику я ни разу не встречал её на реальных проектах. Обычно же как: ключ, данные, TTL — и погнали дальше.Кароч! Рассказываю...
Делал я одну фичу. Суть её сейчас не важна, но появилась необходимость складывать данные, получаемые в ходе работы, в кэш. Ну надо так надо - складываем. А что делают с кэшированными данными? Правильно — периодически чистят для поддержания гигиены и актуальности. И вот тут нашла коса на камень.
Ключи кэша в данной фиче составные и зависят от ряда параметров. Ключи примерно такие —
cache.for.feature.key1.key2.key3. И их конечное количество неизвестно. Ну как неизвестно... Примерно дохреналиард их. И как это всё очищать спросите вы. Ведь спросите же?
Вариантов решения вроде бы хватает. Можно хранить список ключей отдельно, можно искать по префиксам, можно генерировать какие-нибудь служебные ключи для очистки, но всё это выглядит как костыли. Не, можно ещё беспощадно сделать —
Yii::$app->cache->flush(). Очищай больше, хрен ли его жалеть! Другое дело — зависимости кэша.
Для своей задачи я использовал:
TagDependency — cвязывает кэшированные данные элемента с одним или несколькими тегами и позволяет инвалидировать данные кэша по этому тэгу.Синтаксис максимально простой и понятный:
Yii::$app->cache->set(
$cacheKey,
$cacheData,
$cacheTtl,
new TagDependency(['tags' => $tag])
);
А инвалидация кэша делается ещё проще:
TagDependency::invalidate(
Yii::$app->cache,
$tag
);
Разумеется, работает это только с кэш-бэкендами, которые поддерживают зависимости, но для типичных Redis, Memcached и файлового кэша проблем обычно не возникает.
И всё — никаких тебе поисков по префиксам, генерации ключей и прочего мракобесия.
Просто, изящно, профессионально!
#php #yii2 #cache #dependency #backend #web #разработка
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2👍1
Читальня. Питер В. Бретт – Трон черепов
– Власть развращает, а абсолютная власть развращает абсолютно –
Новая порция приключений на просторах Тесы.
К началу 4-го тома события цикла окончательно разделились на две истории. Мир живёт сам по себе, а Избавители — сами по себе. Да, их пути ещё пересекаются отдельными оказиями, но в целом это уже две разные истории.
У Избавителей есть дерзкий план покончить с подземниками раз и навсегда, и они его придерживаютя. Хотя в этой книге избранные отходят на второй план, без экшена не обошлось — будут и сражения, и магия, и копья, и метки.
А вот остальной мир занят более приземлёнными вещами — борьбой за власть и финансовые потоки. Как только мессии канули в лету после эпичной битвы, места вождей внезапно оказались вакантны, и привычная человеческая сущность вылезла наружу.
Первенцы Ахмана искренне желают смерти друг другу и так же искренне хотят усесться на Трон Черепов. Но на пути к заветному стулу стоят и мать, и дядя. И даже Аббан пристраивается сбоку бантиком, чтобы оказаться как можно ближе к трону. Аббан вообще сам себе на уме парень — хорош, чертяка!
Но и северяне времени даром не теряют. Играют тоньше — интриги, союзы, предательства и прочая подковёрная возня. Даже Лиша умудрилась вляпаться во власть, которой никогда особо не искала.
Магическая часть мира последовательно развивается — появляются новые метки, старые комбинируются в неожиданные конструкции, магия становится доступнее и превращается во что-то вроде прикладной науки.
Так же появляется ещё больше новых персонажей. Хотя их уже накопилось столько, что хватило бы ещё на несколько томов приключений, пока Избавители занимаются спасением мира.
По гамбургскому счёту получается странная книга. Событий много. Персонажей много. Политики очень много. А вот основной сюжет почти не двигается вперёд.
В то же время заскучать окончательно не получится. Здесь гибнут важные персонажи, рушатся планы, армии терпят поражения, а некоторые герои внезапно заканчивают свой путь раньше, чем ожидаешь. Но всё это воспринимается скорее как хроника борьбы за власть.
Итого: читать интересно, но впервые поймал себя на мысли, что местами было скучно. Не из-за отсутствия событий — их как раз хватает. Просто почти все они второстепенны и мало влияют на главное противостояние людей и демонов.
7 кастратов из 10.
#книги #почитать #ПитерВБретт #Бретт #ВселеннаяМеченого #ТронЧерепов #тёмное #фентези #магия #монстры
— Обзор первой книги - Меченый
— Обзор второй книги - Копьё пустыни
— Обзор третьей книги - Дневная битва
– Власть развращает, а абсолютная власть развращает абсолютно –
Новая порция приключений на просторах Тесы.
К началу 4-го тома события цикла окончательно разделились на две истории. Мир живёт сам по себе, а Избавители — сами по себе. Да, их пути ещё пересекаются отдельными оказиями, но в целом это уже две разные истории.
У Избавителей есть дерзкий план покончить с подземниками раз и навсегда, и они его придерживаютя. Хотя в этой книге избранные отходят на второй план, без экшена не обошлось — будут и сражения, и магия, и копья, и метки.
А вот остальной мир занят более приземлёнными вещами — борьбой за власть и финансовые потоки. Как только мессии канули в лету после эпичной битвы, места вождей внезапно оказались вакантны, и привычная человеческая сущность вылезла наружу.
Первенцы Ахмана искренне желают смерти друг другу и так же искренне хотят усесться на Трон Черепов. Но на пути к заветному стулу стоят и мать, и дядя. И даже Аббан пристраивается сбоку бантиком, чтобы оказаться как можно ближе к трону. Аббан вообще сам себе на уме парень — хорош, чертяка!
Но и северяне времени даром не теряют. Играют тоньше — интриги, союзы, предательства и прочая подковёрная возня. Даже Лиша умудрилась вляпаться во власть, которой никогда особо не искала.
Магическая часть мира последовательно развивается — появляются новые метки, старые комбинируются в неожиданные конструкции, магия становится доступнее и превращается во что-то вроде прикладной науки.
Так же появляется ещё больше новых персонажей. Хотя их уже накопилось столько, что хватило бы ещё на несколько томов приключений, пока Избавители занимаются спасением мира.
По гамбургскому счёту получается странная книга. Событий много. Персонажей много. Политики очень много. А вот основной сюжет почти не двигается вперёд.
В то же время заскучать окончательно не получится. Здесь гибнут важные персонажи, рушатся планы, армии терпят поражения, а некоторые герои внезапно заканчивают свой путь раньше, чем ожидаешь. Но всё это воспринимается скорее как хроника борьбы за власть.
Итого: читать интересно, но впервые поймал себя на мысли, что местами было скучно. Не из-за отсутствия событий — их как раз хватает. Просто почти все они второстепенны и мало влияют на главное противостояние людей и демонов.
7 кастратов из 10.
#книги #почитать #ПитерВБретт #Бретт #ВселеннаяМеченого #ТронЧерепов #тёмное #фентези #магия #монстры
❤2👍2
Когда Sanctum слишком старается
— Или как перестать насиловать БД UPDATE'ами —
TL;DR
Да что вы знаете о бестолковой работе! А серверы знают. И тоже устают, когда их заставляют выполнять совершенно лишние операции.
Поговорим немного об оптимизации API, а в частности, снизим немного нагрузку на БД при использовании
Туфля не мой, но решение полезное, что не рассказать о нём было бы преступлением.
В чём соль:
Мне сложно представить бизнесовую задачу, где действительно важно знать время использования токена с точностью до каждого запроса. А посему можем слегка умерить энтузиазм
Но мы пойдём другим путём и вынесем механику в универсальный трейт, который можно использовать и в других моделях.
Что тут происходит:
–
–
– если прошло меньше чем
– во всех остальных случаях — сохраняем как обычно через
А в самой модели перепишем
Получается своеобразный rate limit для самого Eloquent.
Ну по красоте же получилось! Сервера точно скажут спасибо.🙏
#php #laravel #sanctum #оптимизация #backend #web #разработка
— Или как перестать насиловать БД UPDATE'ами —
TL;DR
Не каждый запрос достоин отдельного UPDATE. Уменьшаем количество обращений к БД без ущерба для бизнес-логики.
Да что вы знаете о бестолковой работе! А серверы знают. И тоже устают, когда их заставляют выполнять совершенно лишние операции.
Поговорим немного об оптимизации API, а в частности, снизим немного нагрузку на БД при использовании
Laravel Sanctum. Туфля не мой, но решение полезное, что не рассказать о нём было бы преступлением.
Костя, привет!🍺
В чём соль:
sanctum, по умолчанию, обновляет поле last_used_at при каждом запросе с токеном. По правде сказать, в большинстве проектов такая точность попросту не нужна. Для небольших аппов такое поведение не критично, но чем выше RPS, тем ощутимее становится лишняя нагрузка на БД. Мне сложно представить бизнесовую задачу, где действительно важно знать время использования токена с точностью до каждого запроса. А посему можем слегка умерить энтузиазм
sanctum и настроить дросселирование, он же тротлинг. Но мы пойдём другим путём и вынесем механику в универсальный трейт, который можно использовать и в других моделях.
trait ThrottlesAttributeSaves
{
protected function shouldThrottleAttributeSave(string $attribute, int $throttleSeconds): bool
{
$dirty = $this->getDirty();
if (!isset($dirty[$attribute]) || count($dirty) !== 1) {
return false;
}
$original = $this->getOriginal($attribute);
if (!$original) {
return false;
}
if (!$original instanceof Carbon) {
$original = Carbon::parse($original);
}
return now()->diffInSeconds($original) < $throttleSeconds;
}
}
Что тут происходит:
–
$dirty = $this->getDirty(); — cмотрим, что изменилось в модели;–
if (!isset($dirty[$attribute]) || count($dirty) !== 1) — если меняется только один атрибут. то включаем троттлинг;– если прошло меньше чем
$throttleSeconds секунд — притворяемся, что сохранили модель, но на самом деле ничего в БД не пишем;– во всех остальных случаях — сохраняем как обычно через
parent::save();А в самой модели перепишем
save():public function save(array $options = []): bool
{
if ($this->shouldThrottleAttributeSave(
'last_used_at',
self::THROTTLE_SECONDS
)) {
return true;
}
return parent::save($options);
}
Получается своеобразный rate limit для самого Eloquent.
Ну по красоте же получилось! Сервера точно скажут спасибо.
#php #laravel #sanctum #оптимизация #backend #web #разработка
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2🔥2
НЛО снова не прилетело, но это не повод не отметить
– Truth, как говорится, is out there! Но это не точно. –
Вчера, 2-го июля, как-то незаметно прошёл День уфолога. Впрочем, всё, что связано с НЛО, обычно проходит незаметно.
А между тем именно 2 июля 1947 года в штате Нью-Мексико, недалеко от городка Розуэлл, местный фермер нашёл на своём ранчо странные обломки, напоминавшие тонкую фольгу со странными символами, которая не поддавалась ни механическому, ни тепловому воздействию. Журналисты тут же раструбили о захваченной летающей тарелке военными. А военные заявили о метеорологическом зонде и о свете с Венеры, который отразился от верхних слоёв атмосферы и вызвал взрыв болотного газа.🛸
Тем не менее именно этот случай считается отправной точкой, сформировавшей большой интерес к уфологии и теориям заговора. А ведь загадок-то тьма-тьмущая:
— Воронежский инцидент октября 1989 года;
— ЧП в пустыне Калахари в мае 1989 года;
— проект «Синяя книга» 1952–1969;
— культовая Зона 51;
— Петрозаводский феномен, произошедший 20 сентября 1977 года;
— бельгийская волна НЛО 1989-1990;
— невероятные Огни Феникса 1997 года;
Да и недавняя активность вокруг НЛО тоже подливает маслица в огонь:
— правительство США публикует очередные рассекреченные материалы об НЛО/UAP — правда, без зелёных человечков в приложении;
— интернет уже связал в одну теорию заговора десяток пропавших и умерших учёных, так или иначе работавших рядом с космосом, оборонкой или ядерной физикой;
— международная академия астронавтики обновила рекомендации SETI и просит учёных не отвечать на внеземные сигналы без международных консультаций уровня ООН. То есть и тут без дейлика не обойтись.
Видимо, агент Малдер всё-таки что-то знал...🛸
Однако, кругов на полях становится всё меньше, тарелки летают только на кухне, йети и чупакабры впали в спячку, а зелёные человечки перестали похищать людей, видя какой дурдом творится на Земле...
Или же на других планетах тоже сокращают финансирование космических программ?
#внезапно #позновательно #изюм #нло
– Truth, как говорится, is out there! Но это не точно. –
Вчера, 2-го июля, как-то незаметно прошёл День уфолога. Впрочем, всё, что связано с НЛО, обычно проходит незаметно.
А между тем именно 2 июля 1947 года в штате Нью-Мексико, недалеко от городка Розуэлл, местный фермер нашёл на своём ранчо странные обломки, напоминавшие тонкую фольгу со странными символами, которая не поддавалась ни механическому, ни тепловому воздействию. Журналисты тут же раструбили о захваченной летающей тарелке военными. А военные заявили о метеорологическом зонде и о свете с Венеры, который отразился от верхних слоёв атмосферы и вызвал взрыв болотного газа.
Тем не менее именно этот случай считается отправной точкой, сформировавшей большой интерес к уфологии и теориям заговора. А ведь загадок-то тьма-тьмущая:
— Воронежский инцидент октября 1989 года;
— ЧП в пустыне Калахари в мае 1989 года;
— проект «Синяя книга» 1952–1969;
— культовая Зона 51;
— Петрозаводский феномен, произошедший 20 сентября 1977 года;
— бельгийская волна НЛО 1989-1990;
— невероятные Огни Феникса 1997 года;
Да и недавняя активность вокруг НЛО тоже подливает маслица в огонь:
— правительство США публикует очередные рассекреченные материалы об НЛО/UAP — правда, без зелёных человечков в приложении;
— интернет уже связал в одну теорию заговора десяток пропавших и умерших учёных, так или иначе работавших рядом с космосом, оборонкой или ядерной физикой;
— международная академия астронавтики обновила рекомендации SETI и просит учёных не отвечать на внеземные сигналы без международных консультаций уровня ООН. То есть и тут без дейлика не обойтись.
Видимо, агент Малдер всё-таки что-то знал...
Однако, кругов на полях становится всё меньше, тарелки летают только на кухне, йети и чупакабры впали в спячку, а зелёные человечки перестали похищать людей, видя какой дурдом творится на Земле...
Или же на других планетах тоже сокращают финансирование космических программ?
#внезапно #позновательно #изюм #нло
Please open Telegram to view this post
VIEW IN TELEGRAM
👾3
Читальня. Ч. Мьевиль – Крысиный король
— Если ты танцуешь под джангл тебе нужен только бас —
В одном мрачном-мрачном Лондоне, на одной мрачной-мрачной улице, в одном мрачном-мрачном доме жил молодой человек с отцом. И однажды с отцом приключилась беда — он выпал из окна.
И жизнь простого британского парня - Гарамонда, Савла Гарамонда - перевернулась с ног на голову. Его задержали, допрашивали и посадили в кутузку. В кутузке жизнь от парня не отстала и переворачивает мир повторно, но не ставит на место, а ещё больше сносит крышу.
И носит по крышам...
Савл сбежал из-под замка благодаря странному незнакомцу и попал в необыкновенный сказочный мир - в мрачный, затхлый, вонючий и дерьмовый мир. Этот андеграундный мир населён различными люмпенами и монархами: крысиный король, паучиный король, птичий король и коварный Флейтист. И эта королевская братия решает некий давний конфликт, возникший между этой разношёрстной компанией и Флейтистом. И Савлу в этом конфликте отведена не последняя роль.
Пока Савл носится по крышам и отсиживается в коллекторах, автор старательно пичкает нас названиями лондонских улиц, переулков и проходных дворов — какая с какой пересекается и под каким углом. Я не пытался даже запомнить - сложно и не нужно, но пытливый ум может взять карту и поводить пальчиком.
Побываем в лондонской канализации - автор, как по мне, очень натуралистично описывает интерьер коллектора, что текст начинает давить на психику узкими проходами, вонью сточных вод и едким запахом крысиной мочи (сам не знаю, но автор, похоже, в вопросе разбирается). Периодически будем наведываться в мусорные баки и доедать что-то недоеденное и не очень-то свежее.
Окунёмся в музыкальный андеграунд и познакомимся с некоторыми аспектами jungle и drum'n'bass. Без этого элемента не существовало бы и истории - он здесь играет ключевую роль.
Признаюсь, упоминание Goldie в тексте выдавило скупую ностальгескую мужскую слезу. И заставило стряхнуть пыль с пары древних треков. Но почему забыли Aphrodite?! Несправедливо!
Драм здесь, драм там. Драааааам! Бам! Бам! Бам!
Много рассуждений о музыке и субкультуре, которые поймут не только лишь все. А под занавес нас ждёт рейв-вечеринка, которая разматывает в хлам вообще всех: людей, крыс, пауков и всех, кто оказался не в том месте и не в то время. Кровища, кишкища, непотребства - вечерина удалась одним словом!
И только инспектор Кроули, задержавший Савла, грустит, подшивая очередные глухари.
Но есть и хорошие новости - в крысином королевстве случился коммунизм.👴
А возможно, вся эта история горячечный бред, вызванный передозом спидов на рейв-вечеринке?
Кто ж знает...
Итого: необычная, мрачная и жестокая история. Понравится - не понравится тут на вкус каждого, но в любом случае книга не останется незамеченной. Такая, что захочется с кем-то обсудить всю ту дичь, что наворотил автор.
8 мусорных баков из 10
#книги #почитать #ЧайнаМьёвиль #КрысиныйКороль #городское #тёмное #фэнтези #необычное #толькобасспасётнас
— Если ты танцуешь под джангл тебе нужен только бас —
В одном мрачном-мрачном Лондоне, на одной мрачной-мрачной улице, в одном мрачном-мрачном доме жил молодой человек с отцом. И однажды с отцом приключилась беда — он выпал из окна.
И жизнь простого британского парня - Гарамонда, Савла Гарамонда - перевернулась с ног на голову. Его задержали, допрашивали и посадили в кутузку. В кутузке жизнь от парня не отстала и переворачивает мир повторно, но не ставит на место, а ещё больше сносит крышу.
И носит по крышам...
Савл сбежал из-под замка благодаря странному незнакомцу и попал в необыкновенный сказочный мир - в мрачный, затхлый, вонючий и дерьмовый мир. Этот андеграундный мир населён различными люмпенами и монархами: крысиный король, паучиный король, птичий король и коварный Флейтист. И эта королевская братия решает некий давний конфликт, возникший между этой разношёрстной компанией и Флейтистом. И Савлу в этом конфликте отведена не последняя роль.
Пока Савл носится по крышам и отсиживается в коллекторах, автор старательно пичкает нас названиями лондонских улиц, переулков и проходных дворов — какая с какой пересекается и под каким углом. Я не пытался даже запомнить - сложно и не нужно, но пытливый ум может взять карту и поводить пальчиком.
Побываем в лондонской канализации - автор, как по мне, очень натуралистично описывает интерьер коллектора, что текст начинает давить на психику узкими проходами, вонью сточных вод и едким запахом крысиной мочи (сам не знаю, но автор, похоже, в вопросе разбирается). Периодически будем наведываться в мусорные баки и доедать что-то недоеденное и не очень-то свежее.
Окунёмся в музыкальный андеграунд и познакомимся с некоторыми аспектами jungle и drum'n'bass. Без этого элемента не существовало бы и истории - он здесь играет ключевую роль.
Признаюсь, упоминание Goldie в тексте выдавило скупую ностальгескую мужскую слезу. И заставило стряхнуть пыль с пары древних треков. Но почему забыли Aphrodite?! Несправедливо!
Драм здесь, драм там. Драааааам! Бам! Бам! Бам!
Много рассуждений о музыке и субкультуре, которые поймут не только лишь все. А под занавес нас ждёт рейв-вечеринка, которая разматывает в хлам вообще всех: людей, крыс, пауков и всех, кто оказался не в том месте и не в то время. Кровища, кишкища, непотребства - вечерина удалась одним словом!
И только инспектор Кроули, задержавший Савла, грустит, подшивая очередные глухари.
Но есть и хорошие новости - в крысином королевстве случился коммунизм.
А возможно, вся эта история горячечный бред, вызванный передозом спидов на рейв-вечеринке?
Кто ж знает...
Итого: необычная, мрачная и жестокая история. Понравится - не понравится тут на вкус каждого, но в любом случае книга не останется незамеченной. Такая, что захочется с кем-то обсудить всю ту дичь, что наворотил автор.
8 мусорных баков из 10
#книги #почитать #ЧайнаМьёвиль #КрысиныйКороль #городское #тёмное #фэнтези #необычное #толькобасспасётнас
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3❤1
Мутанты на проводе или Всевидящий MutationObserver
— Когда мир перестаёт быть реактивным, остаётся только наблюдать —
TL;DR:
Давненько у нас не было фронтовых баек, а пожалуй что вот оно!
👩💻 Уютный мир: ламповый laravel, приятные vue-компоненты, встроенные в шаблоны. Всё живёт в безмятежном неведении надвигающейся катастрофы.
👩💻 Но тут появляется внешний JS-скрипт, который начинает управлять состоянием vue-компонента извне. В частности - открывает попап, а vue-форма внутри должна менять своё поведение.
Должна, но не может!
Классические приемы не работают:🤦♂️
— Пропсы не пробросить - компонент уже смонтирован;
— События не проэмитить - нет родителя;
— Пересоздавать компонент с переносом логики - слишком жирно. Да и внешний скрипт менять нельзя.
Можно было бы отчаяться и уйти из IT на ферму кроликов разводить, но на помощь приходят мутанты-наблюдатели!🐢
Да, MutationObserver - наше спасение. Всевидящее Око Саурона в мире DOM.
Создаём наблюдателя. Теперь он в засаде и зорко наблюдает за всеми изменениями у родителя:
Но что бы наблюдатель был не слишком наблюдателен, ограничим его кругозор через фильтр:
Ну и, конечно, по-джентльменски освобождаем наблюдателя при смерти компонента.
Если состояние меняется вне зоны реактивности компонента - это не приговор.
Мутанты среди нас, и они всегда помогут!❤️
#vue #mutationobserver #javascript #frontend #web #разработка
— Когда мир перестаёт быть реактивным, остаётся только наблюдать —
TL;DR:
Иногда не нужно менять архитектуру. Достаточно наблюдать и DOM сам расскажет, что произошло.
Давненько у нас не было фронтовых баек, а пожалуй что вот оно!
Должна, но не может!
Классические приемы не работают:
— Пропсы не пробросить - компонент уже смонтирован;
— События не проэмитить - нет родителя;
— Пересоздавать компонент с переносом логики - слишком жирно. Да и внешний скрипт менять нельзя.
Можно было бы отчаяться и уйти из IT на ферму кроликов разводить, но на помощь приходят мутанты-наблюдатели!
Да, MutationObserver - наше спасение. Всевидящее Око Саурона в мире DOM.
Создаём наблюдателя. Теперь он в засаде и зорко наблюдает за всеми изменениями у родителя:
const component = el.parentElement as HTMLDivElement | null;
let observer: MutationObserver | null = null;
onMounted(() => {
observer = new MutationObserver(() => {
if (component.classList.contains('popup_active')) {
// наша логика
}
})
observer.observe(component, {
attributes: true,
attributeFilter: ['class'],
});
});
Но что бы наблюдатель был не слишком наблюдателен, ограничим его кругозор через фильтр:
attributeFilter и следим строго за классом.Ну и, конечно, по-джентльменски освобождаем наблюдателя при смерти компонента.
onUnmounted(() => {
observer?.disconnect();
observer = null;
});Если состояние меняется вне зоны реактивности компонента - это не приговор.
Мутанты среди нас, и они всегда помогут!
#vue #mutationobserver #javascript #frontend #web #разработка
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Достучаться до Reverb: без зависимости от окружения
– Как подружить Laravel Reverb с Nginx без головной боли –
tl;dr:
Давненько слышал про этот пакет, но всё как-то руки не доходили. А тут случилась оказия - надо настроить оповещение для редакторов, если кто-то уже правит контент.
Ни слова больше!
Разумеется вариант с периодической долбёжкой сервера запросами по таймеру был отметён сразу. Таким дети в пубертате занимаются, а мы то уже огого - знаем что такое WebSockets!💡
Вариант с socket.io тоже был отметён - чай не 2010 год на дворе. Чатов на нём за эту жизнь уже написано достаточно, да и прочие realtime-приложения реализованы. Хотелось попробовать что-нибудь новое.
Кароч! Reverb - наш герой сегодняшнего дня.
— Умеет только websockets, без fallback-механизмов (long polling и проч.);
— Клиентская либа laravel-echo из коробки;
— Публичные, приватные и presence-каналы, со стандартной Laravel-авторизацией;
— Self-hosted, нативно дружит с Laravel и удобный режим отладки;
Но, если бы на этом всё, я бы и писать не стал.
Сетап Reverb оказался не без сюрпризов. Ничего криминального, но некоторые особенности таки застали меня врасплох.
Docker, Reverb и первые грабли
В локальном окружении я использую Docker, поэтому Reverb оформлен отдельным сервисом.
Настроек у Reverb из коробки довольно много, что сначала и ввело меня в некоторое замешательство.
Локально всё завелось, я довольно потёр руки, выкатил это добро на сервер — и... Не работает!
Выделывать коленца стал фронт, потому что сборка зависит от окружения.🤪
Идея, в итоге такая: браузер всегда подключается к WebSocket на текущем домене, а nginx проксирует /app в Reverb.
То есть снаружи адрес всегда выглядит одинаково:
А что там дальше —
1. Упрощаем Echo
Убираем из
Оставляем только ключ:
2. Настраиваем Laravel и сам Reverb
Серверную часть Laravel будет читать из
У Reverb фактически есть два разных набора координат:
3. Ставим nginx посередине
Добавляем проксирование WebSocket-соединений:
Теперь браузер локально ходит так:
Итоговая логика
Фронт в итоге собирается одинаково для всех окружений, а бэкенд легко настраивается только через env и nginx upstream. Никаких environment-specific во фронте, отдельных билдов и плясок вокруг конфигурации.
Это сильно упрощает жизнь, экономит время, нервы и делает стул регулярным.
#php #laravel #reverb #websockets #backend #web #разработка
– Как подружить Laravel Reverb с Nginx без головной боли –
tl;dr:
Подключаемся к WebSocket на текущем домене, /app проксируем через nginx — и получаем один билд для всех окружений.
Давненько слышал про этот пакет, но всё как-то руки не доходили. А тут случилась оказия - надо настроить оповещение для редакторов, если кто-то уже правит контент.
Ни слова больше!
Разумеется вариант с периодической долбёжкой сервера запросами по таймеру был отметён сразу. Таким дети в пубертате занимаются, а мы то уже огого - знаем что такое WebSockets!
Вариант с socket.io тоже был отметён - чай не 2010 год на дворе. Чатов на нём за эту жизнь уже написано достаточно, да и прочие realtime-приложения реализованы. Хотелось попробовать что-нибудь новое.
Кароч! Reverb - наш герой сегодняшнего дня.
— Умеет только websockets, без fallback-механизмов (long polling и проч.);
— Клиентская либа laravel-echo из коробки;
— Публичные, приватные и presence-каналы, со стандартной Laravel-авторизацией;
— Self-hosted, нативно дружит с Laravel и удобный режим отладки;
Но, если бы на этом всё, я бы и писать не стал.
Сетап Reverb оказался не без сюрпризов. Ничего криминального, но некоторые особенности таки застали меня врасплох.
Docker, Reverb и первые грабли
В локальном окружении я использую Docker, поэтому Reverb оформлен отдельным сервисом.
reverb:
build:
context: ./dockerfiles
dockerfile: php/Dockerfile
args:
NGINX_PATH: ${NGINX_PATH}
volumes: !override
- ./src:${NGINX_PATH}
env_file:
- ./src/.env
environment:
NGINX_PATH: ${NGINX_PATH}
command: php artisan reverb:start
depends_on:
- php
- redis
- queue
restart: unless-stopped
Настроек у Reverb из коробки довольно много, что сначала и ввело меня в некоторое замешательство.
Локально всё завелось, я довольно потёр руки, выкатил это добро на сервер — и... Не работает!
Выделывать коленца стал фронт, потому что сборка зависит от окружения.
О, сколько нам открытий чудных
Готовят просвещенья дух,
И опыт, сын ошибок трудных...
Идея, в итоге такая: браузер всегда подключается к WebSocket на текущем домене, а nginx проксирует /app в Reverb.
То есть снаружи адрес всегда выглядит одинаково:
wss://мой-крутой-сервис.рф/app/...А что там дальше —
Docker, localhost или отдельный сервер — браузеру совершенно неинтересно.1. Упрощаем Echo
Убираем из
echo.js окружение-зависимые хосты и прочие радости:window.Echo = new Echo({
broadcaster: 'reverb',
key: import.meta.env.VITE_REVERB_APP_KEY,
wsHost: window.location.hostname,
wsPort: window.location.protocol === 'https:' ? 443 : 80,
wssPort: 443,
forceTLS: window.location.protocol === 'https:',
enabledTransports: ['ws', 'wss'],
});Оставляем только ключ:
VITE_REVERB_APP_KEY="${REVERB_APP_KEY}"2. Настраиваем Laravel и сам Reverb
Серверную часть Laravel будет читать из
.env:REVERB_HOST=reverb
REVERB_PORT=8888
REVERB_SCHEME=http
REVERB_SERVER_HOST=0.0.0.0
REVERB_SERVER_PORT=8888
У Reverb фактически есть два разных набора координат:
REVERB_SERVER_* — где слушает сам ReverbREVERB_* — куда Laravel отправляет событияVITE_REVERB_* — куда подключается браузер3. Ставим nginx посередине
Добавляем проксирование WebSocket-соединений:
location /app {
proxy_http_version 1.1;
proxy_pass http://reverb:8888;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_read_timeout 60s;
proxy_send_timeout 60s;
}Теперь браузер локально ходит так:
wss://мой-крутой-сервис.рф/app/...Итоговая логика
Browser -> текущий домен /app -> nginx -> Reverb
Laravel -> внутренний REVERB_HOST:8888 -> Reverb
Фронт в итоге собирается одинаково для всех окружений, а бэкенд легко настраивается только через env и nginx upstream. Никаких environment-specific во фронте, отдельных билдов и плясок вокруг конфигурации.
Это сильно упрощает жизнь, экономит время, нервы и делает стул регулярным.
#php #laravel #reverb #websockets #backend #web #разработка
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Неуникальная уникальность, и при чем тут дни рождения
– Ведь в мире их еще миллиарда четыре! А быть может и пять, как знать? –
tl;dr
Наткнулся на днях на интересное понятие - Парадокс дней рождений (birthday paradox). Это ситуация, когда интуиция нас подводит в оценке вероятностей.
В чём суть
Классический пример - кажется, что, раз в году 365 дней, то чтобы с вероятностью 50% у кого‑то в группе совпали дни рождения, то понадобится (на глазок) что-то около половины от 365 - то есть под две сотни человек. Но математика говорит другое: достаточно всего 23 человека, чтобы вероятность совпадения хотя бы у двоих была примерно 50,7%.
Так происходит потому, что сравнивается не "один человек со всеми датами", а все пары людей между собой.
Для 23 человек пар будет:
У каждой пары есть шанс совпасть. И чем больше таких пар, тем быстрее растёт вероятность, что хотя бы в одной из них случится совпадение.
Почему об этом важно помнить в типовых задачах?
Зачастую мы генерируем всякие уникальные значения: UUID, slug, реферальный код и прочие идентификаторы каким-нибудь эдаким способом:
Разберём
Один hex-символ хранит 4 бита. Значит 8 hex-символов - это 32 бита. А это, на минуточку,🤑 . Дофига, не правда ли? На первый взгляд много, но из-за парадокса коллизии становятся вероятными намного раньше.
Вероятность хотя бы одной коллизии можно приблизительно оценить по формуле:
Оценочно:
То есть проблема не в том, что 4 млрд быстро закончатся, а в том, что при случайном распределении два значения могут получить один и тот же 8-символьный slug уже на десятках тысяч записей.
Как исправить
Увеличить пространство значений, чтобы сделать коллизию практически невозможной.
Например, 16 hex-символов — это уже 64 бита. Для 100 000 записей вероятность коллизии составляет примерно 0,000000027%.
А если идентификатор обязан быть уникальным, то никакая теория вероятностей не заменит
—
Дурацкая математика! Вечно портит красивые решения!😵
#php #коллизии #хеширование #birthdayparadox #backend #web #разработка
– Ведь в мире их еще миллиарда четыре! А быть может и пять, как знать? –
tl;dr
Почему 2^32 вариантов — не так много, как кажется?
Немного математики о коллизиях и обманчивой уникальности.
Наткнулся на днях на интересное понятие - Парадокс дней рождений (birthday paradox). Это ситуация, когда интуиция нас подводит в оценке вероятностей.
В чём суть
Классический пример - кажется, что, раз в году 365 дней, то чтобы с вероятностью 50% у кого‑то в группе совпали дни рождения, то понадобится (на глазок) что-то около половины от 365 - то есть под две сотни человек. Но математика говорит другое: достаточно всего 23 человека, чтобы вероятность совпадения хотя бы у двоих была примерно 50,7%.
Так происходит потому, что сравнивается не "один человек со всеми датами", а все пары людей между собой.
Для 23 человек пар будет:
23 * 22 / 2 = 253 парыУ каждой пары есть шанс совпасть. И чем больше таких пар, тем быстрее растёт вероятность, что хотя бы в одной из них случится совпадение.
Почему об этом важно помнить в типовых задачах?
Зачастую мы генерируем всякие уникальные значения: UUID, slug, реферальный код и прочие идентификаторы каким-нибудь эдаким способом:
$slug = substr(sha1($string), 0, 8)Разберём
Один hex-символ хранит 4 бита. Значит 8 hex-символов - это 32 бита. А это, на минуточку,
2^32, примерно 4,29 млрд возможных значений Вероятность хотя бы одной коллизии можно приблизительно оценить по формуле:
p ≈ 1 - exp(-n(n - 1) / (2 × 2^32)).Оценочно:
10 000 значений -> ~1.2% шанс коллизии
50 000 значений -> ~25% шанс коллизии
77 000 значений -> ~50% шанс коллизии
100 000 значений -> ~69% шанс коллизии
То есть проблема не в том, что 4 млрд быстро закончатся, а в том, что при случайном распределении два значения могут получить один и тот же 8-символьный slug уже на десятках тысяч записей.
Как исправить
Увеличить пространство значений, чтобы сделать коллизию практически невозможной.
Например, 16 hex-символов — это уже 64 бита. Для 100 000 записей вероятность коллизии составляет примерно 0,000000027%.
А если идентификатор обязан быть уникальным, то никакая теория вероятностей не заменит
UNIQUE на поле и обработку коллизии при генерации.—
Дурацкая математика! Вечно портит красивые решения!
#php #коллизии #хеширование #birthdayparadox #backend #web #разработка
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Не долбимся как кролики с RabbitMQ и yii2-queue
– retry, delay, exponential backoff и немного jitter без лишнего насилия над очередями –
tl;dr
Ну что же, у нас классика на столе -
У очередей настроены попытки - пусть 5 для определённости.
Как будто-бы всё хорошо:
Но есть нюанс.
При использовании
То есть внешний сервис прилёг, API отвечает ошибкой - а мы такие:
😃
Улучшаем - добавляем паузу
Сам
Теперь между попытками появляется простенький linear backoff:
Если не нравится линейный вариант, то можно сделать exponential backoff:
И тогда будет
Нет предела совершенству - добавляем jitter
Представим, что в очереди 10 000 сообщений. Все получили ошибку отправки уведомления через внешний сервис примерно одновременно и происходит retry для всей очереди.
Йеее - словили thundering herd problem, он же «эффект громового стада»!😆
Чтобы не положить внешний сервис окончательно или не словить его
Full jitter -
Equal Jitter - гарантированно ждём хотя бы половину задержки, а остальное отдаём на волю рандома.
Decorrelated Jitter - cледующая задержка зависит от предыдущей (оставим для самостоятельного изучения😄 )
🚨 !!! ВАЖНО !!!
Уход на
Не возвращает
А именно падает:
#php #yii2 #rabbitmq #yii2queue #queues #retry #amqp #backend #web #разработка
– retry, delay, exponential backoff и немного jitter без лишнего насилия над очередями –
tl;dr
yii2-queue с amqp_interop может повторно отправлять упавшую задачу практически сразу. Добавляем DeliveryDelay - и получаем retry с паузой.
Ну что же, у нас классика на столе -
yii2 и система нотификаций, реализованная через yii2-queue и rabbitmq в качестве брокера очередей. У очередей настроены попытки - пусть 5 для определённости.
Как будто-бы всё хорошо:
джоба падает → yii2-queue делает retry → жизнь продолжается.
Но есть нюанс.
При использовании
amqp_interop повторная отправка сообщения идёт через redeliver(). И идёт она сразу.То есть внешний сервис прилёг, API отвечает ошибкой - а мы такие:
— Не получилось?Не
— Не получилось.
— А сейчас?
— Нет.
— А сейчас?
— Всё ещё нет.
— А СЕЙЧАС?!
retry, а тревожный разработчик какой-то перед дедлайном. Улучшаем - добавляем паузу
Сам
yii\queue\amqp_interop\Queue почти всё уже умеет. Но немножечко надо допилить метод redeliver и добавить отправку сообщений с задержкой.protected function redeliver(AmqpMessage $message): void
{
$attempt = (int)$message->getProperty(self::ATTEMPT, 1);
$delay = $attempt * 60;
$newMessage = $this->context->createMessage(
$message->getBody(),
$message->getProperties(),
$message->getHeaders()
);
$newMessage->setDeliveryMode($message->getDeliveryMode());
$newMessage->setProperty(self::ATTEMPT, $attempt + 1);
$newMessage->setProperty(self::DELAY, $delay);
$producer = $this->context->createProducer();
$producer->setDeliveryDelay($delay * 1000);
$producer->send($this->context->createQueue($this->queueName), $newMessage);
}
Теперь между попытками появляется простенький linear backoff:
1 retry → 60 секунд
2 retry → 120 секунд
3 retry → 180 секунд
...
Если не нравится линейный вариант, то можно сделать exponential backoff:
$delay = 60 * (2 ** ($attempt - 1));И тогда будет
attempt 1 → 60 сек
attempt 2 → 120 сек
attempt 3 → 240 сек
attempt 4 → 480 сек
...
Нет предела совершенству - добавляем jitter
Представим, что в очереди 10 000 сообщений. Все получили ошибку отправки уведомления через внешний сервис примерно одновременно и происходит retry для всей очереди.
Йеее - словили thundering herd problem, он же «эффект громового стада»!
Чтобы не положить внешний сервис окончательно или не словить его
rate limit, добавим немного случайности:Full jitter -
retry распределится по всему диапазону от 0 до $delay.$jitter = random_int(0, $delay);Equal Jitter - гарантированно ждём хотя бы половину задержки, а остальное отдаём на волю рандома.
$half = (int) ($delay / 2);
$jitter = $half + random_int(0, $half);
Decorrelated Jitter - cледующая задержка зависит от предыдущей (оставим для самостоятельного изучения
Уход на
retry с новой попыткой срабатывает только тогда, когда джоба выбрасывает Exception. Не возвращает
false, null или что-нибудь ещё в духе "ну, не шмогла". А именно падает:
throw new RuntimeException('Notification sending failed'); Иначе для yii2-queue джоба успешно завершилась и повторять там, собственно, нечего.#php #yii2 #rabbitmq #yii2queue #queues #retry #amqp #backend #web #разработка
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Некоторое время назад, я таки решил разделить контент по тематике и о прочитанном развлекательном пишу тут не далеко - в паре кликов. А тут оставлю техническое.
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from Читательский билет
Алишер Бекет - Сэхсвет
– Всё пожирается смертью; ведь гибель — закон, а не кара –
Пожалуй, начну в начале - с конца. Да! Однозначно читать!
И вот почему.
С первых страниц книги нас встречает прекрасное человеческое будущее. Люди летают по городам в гравикарах. Общественный транспорт, который тут незатейливо называется транспОртом, может вас доставить прямо из города прямо на северный полюс за пару-тройку часов. Здесь многие болезни побеждены, а импланты не только увеличивают грудь, но и решают очень даже серьёзные проблемы со здоровьем, а не только косметические хотелки. Но, собственно, сделать динамическую смену цвета глаз тоже запросто.
Кстати, встречает нас местный бомж, который не ел уже несколько дней и шарящийся по мусорным бакам в надежде найти что-нибудь, что ещё не отрастило свои ложноножки и не будет против употребления в пищу.
В общем, всё как мы любим - богатство, комфорт, роскошь, социальное неравенство, чёрный рынок трансплантологии и имплантологии, наркоманы и имплантоманы.
Дааа! Родной неоновый киберпанк завезли!
Но сколько бы у тебя ни было денег, имплантов и гравикаров, смерть здесь всё равно приходит за каждым. Причём буквально - в капюшоне и с правом выбора - гульнуть напоследок на все деньги и уйти в мир иной или сыграть в рулетку и попытаться остаться в этом мире. Но не всё так просто...
И только ты начинаешь погружаться в этот мир и проблемы героев: Джил, Кросстана, Мэйтта, как неожиданно человечество начинает месить друг друга в кровавую кашу. Появляются телепаты и начинают вытворять с окружающими разное нехорошее - да так, что где-то в сторонке нервно закуривает «Эльфийская песнь» Линна Окамото.
И ты такой - да какого хера случилось-то?!
И вот ты вроде бы смирился с мыслью - ну ок, пусть будут телепаты. Импланты есть. Смерть приходит с дождём. Почему бы и не телепаты! Мало ли, как коротит мозги у одержимых на фоне приёма интокса.
И тут - херак! - тебя выкидывают вообще в другое время, а человечество стало бессмертным.
И ты такой - да что происходит-то?!
А происходит то, что все те события, которые книга до этого заботливо наваливала тебе на голову, внезапно начинают обретать смысл. Киберпанк, импланты, старики, особенности Джил, Кросса и Мэйтта... Телепатия в конце концов! Одно цепляется за другое, вопросы начинают получать ответы, а предыдущие события обретают совершенно новый смысл.
И ты такой — да лаааадно!... Вон оно чо, Михалыч!
И чем больше впитываешь объяснения, тем сильнее поражает масштаб происходящего. Волосы начинают шевелиться против ветра, а мурашки маршируют строем под звуки «Прощание славянки».
Да вы даже не представляете, кто правит миром!
И вот ты уже сидишь накачанный, с кипящими мозгами, листаешь дальше и думаешь: Ну давай! Ломай меня полностью!
И финал делает это - обламывает!
Не ломает, а обламывает, Карл!
И ты такой — э-э-э... чего?
Не, мысль понятна. Причина замеса ясна. Но после всей той накачки в предыдущих частях я ожидал от финала чего-то другого. Чего-то столь же крышесносного, как всё, что к нему привело.
Честно, я был уже готов расчехлять десятку на своём личном шкалометре, но финал...
Эх, финал...
Итого: отличный киберпанк, интересные концепции будущего человечества, сюжет, раз за разом переворачивающий доску происходящего, и сногсшибательные объяснения всего движа. И финал, оставивший один большой вопрос: «Для чего?» Для чего вся эта суета была?
Тем не менее книга однозначно заслуживает внимания.
9 интоксов из 10
#обзор #АлишерБекет #Сэхсвет #научнаяфантастика #киберпанк #трансгуманизм #бессмертие
– Всё пожирается смертью; ведь гибель — закон, а не кара –
Пожалуй, начну в начале - с конца. Да! Однозначно читать!
И вот почему.
С первых страниц книги нас встречает прекрасное человеческое будущее. Люди летают по городам в гравикарах. Общественный транспорт, который тут незатейливо называется транспОртом, может вас доставить прямо из города прямо на северный полюс за пару-тройку часов. Здесь многие болезни побеждены, а импланты не только увеличивают грудь, но и решают очень даже серьёзные проблемы со здоровьем, а не только косметические хотелки. Но, собственно, сделать динамическую смену цвета глаз тоже запросто.
Кстати, встречает нас местный бомж, который не ел уже несколько дней и шарящийся по мусорным бакам в надежде найти что-нибудь, что ещё не отрастило свои ложноножки и не будет против употребления в пищу.
В общем, всё как мы любим - богатство, комфорт, роскошь, социальное неравенство, чёрный рынок трансплантологии и имплантологии, наркоманы и имплантоманы.
Дааа! Родной неоновый киберпанк завезли!
Но сколько бы у тебя ни было денег, имплантов и гравикаров, смерть здесь всё равно приходит за каждым. Причём буквально - в капюшоне и с правом выбора - гульнуть напоследок на все деньги и уйти в мир иной или сыграть в рулетку и попытаться остаться в этом мире. Но не всё так просто...
И только ты начинаешь погружаться в этот мир и проблемы героев: Джил, Кросстана, Мэйтта, как неожиданно человечество начинает месить друг друга в кровавую кашу. Появляются телепаты и начинают вытворять с окружающими разное нехорошее - да так, что где-то в сторонке нервно закуривает «Эльфийская песнь» Линна Окамото.
И ты такой - да какого хера случилось-то?!
И вот ты вроде бы смирился с мыслью - ну ок, пусть будут телепаты. Импланты есть. Смерть приходит с дождём. Почему бы и не телепаты! Мало ли, как коротит мозги у одержимых на фоне приёма интокса.
И тут - херак! - тебя выкидывают вообще в другое время, а человечество стало бессмертным.
И ты такой - да что происходит-то?!
А происходит то, что все те события, которые книга до этого заботливо наваливала тебе на голову, внезапно начинают обретать смысл. Киберпанк, импланты, старики, особенности Джил, Кросса и Мэйтта... Телепатия в конце концов! Одно цепляется за другое, вопросы начинают получать ответы, а предыдущие события обретают совершенно новый смысл.
И ты такой — да лаааадно!... Вон оно чо, Михалыч!
И чем больше впитываешь объяснения, тем сильнее поражает масштаб происходящего. Волосы начинают шевелиться против ветра, а мурашки маршируют строем под звуки «Прощание славянки».
Да вы даже не представляете, кто правит миром!
И вот ты уже сидишь накачанный, с кипящими мозгами, листаешь дальше и думаешь: Ну давай! Ломай меня полностью!
И финал делает это - обламывает!
Не ломает, а обламывает, Карл!
И ты такой — э-э-э... чего?
Не, мысль понятна. Причина замеса ясна. Но после всей той накачки в предыдущих частях я ожидал от финала чего-то другого. Чего-то столь же крышесносного, как всё, что к нему привело.
Честно, я был уже готов расчехлять десятку на своём личном шкалометре, но финал...
Эх, финал...
Итого: отличный киберпанк, интересные концепции будущего человечества, сюжет, раз за разом переворачивающий доску происходящего, и сногсшибательные объяснения всего движа. И финал, оставивший один большой вопрос: «Для чего?» Для чего вся эта суета была?
Тем не менее книга однозначно заслуживает внимания.
9 интоксов из 10
#обзор #АлишерБекет #Сэхсвет #научнаяфантастика #киберпанк #трансгуманизм #бессмертие
❤2🔥2