SELECT FOR UPDATE в Postgres фактически делает записьВ heap-странице Postgres у каждого tuple есть заголовок header с метаданными.
Когда транзакция выполняет SELECT FOR UPDATE, у найденных tuple (по предикату) обновляется header: они помечаются как залоченные, а атрибут xmax фиксирует XID транзакции, которая поставила лок.
Конкретно выставляются два бита в infomask заголовка: HEAP_XMAX_EXCL_LOCK и HEAP_XMAX_LOCK_ONLY.
Из-за этого страница становится dirty и это также попадает в WAL, который потом может уехать на standby-реплику.
Позже dirty-страница может быть сброшена на диск background writer-ом.
На commit эти биты очищаются.
Забавно, что операция чтения может породить приличный объём write I/O.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1
Хорошие новости для пользователей Postgres под конец года. Команда TimescaleDB выпустила и открыла исходники расширения pg_textsearch.
В Postgres уже есть встроенный полнотекстовый поиск, а это расширение делает его более современным и продвинутым за счёт добавления ранжирования BM25.
👉 @BackendPortal
В Postgres уже есть встроенный полнотекстовый поиск, а это расширение делает его более современным и продвинутым за счёт добавления ранжирования BM25.
Please open Telegram to view this post
VIEW IN TELEGRAM
Tiger Data Blog
From ts_rank to BM25. Introducing pg_textsearch: True BM25 Ranking and Hybrid Retrieval Inside Postgres | Tiger Data
pg_textsearch brings BM25 ranking to enable hybrid search to Postgres. Build RAG systems with keyword precision and vector semantics in one database.
Почему JSON жрёт ваш CPU
Ваш API тормозит. Вы грешите на базу. Потом на сеть. А реальным бутылочным горлышком может быть язык, на котором вы общаетесь.
JSON — это не формат данных. Это текстовая строка.
Каждый раз, когда вы отправляете {"id": 12345}, сервер платит скрытый налог на парсинг. Даже с современными SIMD-оптимизированными парсерами текст упирается в архитектурные ограничения, которых нет у бинарных форматов.
Разбор по инженерке:
1. Стоимость для CPU (машина состояний против арифметики)
JSON (текст):
Чтобы прочитать число 12345, CPU получает поток байт. Даже самые быстрые парсеры вроде simdjson вынуждены работать как машина состояний:
- искать структурные разделители (: и ,)
- проверять escape-последовательности ()
- конвертировать число: проход по ASCII-символам, вычитание '0', умножение на степени 10 и суммирование
Всё это — ветвления, промахи предсказателя и обращения к памяти.
-» Protobuf (бинарь):
Передаёт либо Varint (для маленьких чисел), либо фиксированную ширину (для больших).
Fixed-width (например, fixed32) — это просто memcpy. Парсинга нет вообще.
-» Varint — чтение байт по одному с проверкой старшего бита (MSB), продолжается ли число.
Итог: декодирование сводится к нескольким битовым сдвигам и маскам. Для числовых нагрузок это гарантированно быстрее любого текстового парсинга.
2. Стоимость по пропускной способности (энтропия против избыточности)
Ключ "status" передаётся снова и снова.
Контраргумент: но gzip же всё сжимает.
Ответ: gzip уменьшает трафик, но увеличивает нагрузку на CPU. Сервер делает Serialize JSON → Compress → Send. Клиент — Decompress → Parse JSON. Вы тратите CPU на сжатие избыточного текста, которого вообще не должно было быть.
--» Protobuf:
Отделяет схему от данных.
В wire-формате строка "status" заменяется ID поля, например 1: [Tag: 1][Value: "active"]. Размер сообщения меньше ещё до компрессии, а значит экономятся CPU-циклы с обеих сторон.
3. Стоимость надёжности
JSON — это схема-при-чтении.
Получатель получает blob и надеется, что id — это число. В коде появляются проверки вида if typeof(id) !== 'number или подключаются валидаторы вроде Zod или Pydantic, которые добавляют ещё один слой runtime-нагрузки.
Protobuf — это схема при записи.
Контракт enforced на границе сериализации. Он не ловит логические ошибки, но гарантирует сохранность типов. Обычно не нужны тяжёлые runtime-валидаторы, чтобы проверить, что Integer — это Integer.
Можно сказать:
JSON отлично подходит для публичных API — его легко дебажить и читать. Но для высоконагруженных микросервисов JSON — это налог.
Переход на gRPC/Protobuf — не сверхчудо. Это просто перенос сложности из парсинг текста в генерацию кода
👉 @BackendPortal
Ваш API тормозит. Вы грешите на базу. Потом на сеть. А реальным бутылочным горлышком может быть язык, на котором вы общаетесь.
JSON — это не формат данных. Это текстовая строка.
Каждый раз, когда вы отправляете {"id": 12345}, сервер платит скрытый налог на парсинг. Даже с современными SIMD-оптимизированными парсерами текст упирается в архитектурные ограничения, которых нет у бинарных форматов.
Разбор по инженерке:
1. Стоимость для CPU (машина состояний против арифметики)
JSON (текст):
Чтобы прочитать число 12345, CPU получает поток байт. Даже самые быстрые парсеры вроде simdjson вынуждены работать как машина состояний:
- искать структурные разделители (: и ,)
- проверять escape-последовательности ()
- конвертировать число: проход по ASCII-символам, вычитание '0', умножение на степени 10 и суммирование
Всё это — ветвления, промахи предсказателя и обращения к памяти.
-» Protobuf (бинарь):
Передаёт либо Varint (для маленьких чисел), либо фиксированную ширину (для больших).
Fixed-width (например, fixed32) — это просто memcpy. Парсинга нет вообще.
-» Varint — чтение байт по одному с проверкой старшего бита (MSB), продолжается ли число.
Итог: декодирование сводится к нескольким битовым сдвигам и маскам. Для числовых нагрузок это гарантированно быстрее любого текстового парсинга.
2. Стоимость по пропускной способности (энтропия против избыточности)
JSON:
[{"status": "active"}, {"status": "active"}]
Ключ "status" передаётся снова и снова.
Контраргумент: но gzip же всё сжимает.
Ответ: gzip уменьшает трафик, но увеличивает нагрузку на CPU. Сервер делает Serialize JSON → Compress → Send. Клиент — Decompress → Parse JSON. Вы тратите CPU на сжатие избыточного текста, которого вообще не должно было быть.
--» Protobuf:
Отделяет схему от данных.
В wire-формате строка "status" заменяется ID поля, например 1: [Tag: 1][Value: "active"]. Размер сообщения меньше ещё до компрессии, а значит экономятся CPU-циклы с обеих сторон.
3. Стоимость надёжности
JSON — это схема-при-чтении.
Получатель получает blob и надеется, что id — это число. В коде появляются проверки вида if typeof(id) !== 'number или подключаются валидаторы вроде Zod или Pydantic, которые добавляют ещё один слой runtime-нагрузки.
Protobuf — это схема при записи.
Контракт enforced на границе сериализации. Он не ловит логические ошибки, но гарантирует сохранность типов. Обычно не нужны тяжёлые runtime-валидаторы, чтобы проверить, что Integer — это Integer.
Можно сказать:
JSON отлично подходит для публичных API — его легко дебажить и читать. Но для высоконагруженных микросервисов JSON — это налог.
Переход на gRPC/Protobuf — не сверхчудо. Это просто перенос сложности из парсинг текста в генерацию кода
Please open Telegram to view this post
VIEW IN TELEGRAM
❤12
Postgres CTE
-» небольшие, читаемые блоки SQL
-» можно тестировать запрос по частям
-» переиспользовать фрагменты SQL в других запросах
👉 @BackendPortal
-» небольшие, читаемые блоки SQL
-» можно тестировать запрос по частям
-» переиспользовать фрагменты SQL в других запросах
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2
В небольшом приложении один HTTP-запрос обычно делает всё.
Например, пользователь регистрируется.
Бэкенд сохраняет пользователя, отправляет welcome-письмо, пишет метрики и только потом отвечает. Работает, но пользователь ждёт дольше, а если что-то ломается посередине, может упасть вся операция.
Проблема в том, что в одном потоке смешиваются критичные и второстепенные задачи.
Создать пользователя -» критично. Отправить welcome-письмо -» нет. Когда всё идёт в одном флоу, у всего одинаковый вес, и приложение начинает тормозить.
В более крупных системах это решают через Message Queue.
Бэкенд выступает как producer -» сохраняет пользователя и кладёт сообщение в очередь с отложенной задачей, например «отправить welcome-email». На этом запрос заканчивается и быстро отдаёт ответ.
Позже один или несколько воркеров забирают сообщение из очереди и выполняют задачу. Если отправка письма упала, её можно ретраить, не затрагивая пользователя.
Так создание пользователя и отправка письма перестают зависеть друг от друга.
Обратная сторона -» в системе появляется больше компонентов и растёт сложность.
👉 @BackendPortal
Например, пользователь регистрируется.
Бэкенд сохраняет пользователя, отправляет welcome-письмо, пишет метрики и только потом отвечает. Работает, но пользователь ждёт дольше, а если что-то ломается посередине, может упасть вся операция.
Проблема в том, что в одном потоке смешиваются критичные и второстепенные задачи.
Создать пользователя -» критично. Отправить welcome-письмо -» нет. Когда всё идёт в одном флоу, у всего одинаковый вес, и приложение начинает тормозить.
В более крупных системах это решают через Message Queue.
Бэкенд выступает как producer -» сохраняет пользователя и кладёт сообщение в очередь с отложенной задачей, например «отправить welcome-email». На этом запрос заканчивается и быстро отдаёт ответ.
Позже один или несколько воркеров забирают сообщение из очереди и выполняют задачу. Если отправка письма упала, её можно ретраить, не затрагивая пользователя.
Так создание пользователя и отправка письма перестают зависеть друг от друга.
Обратная сторона -» в системе появляется больше компонентов и растёт сложность.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5
Обобщённые инвертированные индексы (GIN) - мощный инструмент в Postgres.
Они хороши тем, что переворачивают привычную модель индексации.
Вместо логики вида: строка с ID 2 содержит значение "become a database expert", индекс хранит обратное соответствие: токен "database" указывает на строки с ID 1, 2 и 3, а "expert" — на строку с ID 2.
GIN-индексу на вход подаётся набор значений для каждой строки, которую нужно проиндексировать. Каждое уникальное значение становится ключом в индексе и сопоставляется с набором CTID (идентификаторов кортежей строк), в которых это значение встречается.
У такого подхода есть несколько сценариев применения, и один из самых популярных - полнотекстовый поиск. В MySQL для этого есть отдельный тип индекса FULLTEXT, а в Postgres похожая функциональность строится на более универсальных GIN-индексах.
Как это выглядит на практике:
(a) Добавляем колонку tsvector в таблицу:
(b) Заполняем её лексемами (нормализованными словами):
(c) Создаём GIN-индекс по лексемам:
(d) И выполняем запросы:
В итоге получаем быстрый и гибкий полнотекстовый поиск прямо внутри Postgres, без отдельных движков и костылей.
👉 @BackendPortal
Они хороши тем, что переворачивают привычную модель индексации.
Вместо логики вида: строка с ID 2 содержит значение "become a database expert", индекс хранит обратное соответствие: токен "database" указывает на строки с ID 1, 2 и 3, а "expert" — на строку с ID 2.
GIN-индексу на вход подаётся набор значений для каждой строки, которую нужно проиндексировать. Каждое уникальное значение становится ключом в индексе и сопоставляется с набором CTID (идентификаторов кортежей строк), в которых это значение встречается.
У такого подхода есть несколько сценариев применения, и один из самых популярных - полнотекстовый поиск. В MySQL для этого есть отдельный тип индекса FULLTEXT, а в Postgres похожая функциональность строится на более универсальных GIN-индексах.
Как это выглядит на практике:
(a) Добавляем колонку tsvector в таблицу:
CREATE TABLE post (
author TEXT,
publish_date DATE,
content TEXT NOT NULL,
search_vector tsvector
);
(b) Заполняем её лексемами (нормализованными словами):
UPDATE post
SET search_vector =
to_tsvector('english', content);
(c) Создаём GIN-индекс по лексемам:
CREATE INDEX post_search_idx
ON post USING GIN(search_vector);
(d) И выполняем запросы:
SELECT * FROM post
WHERE search_vector @@
to_tsquery('english', 'database & expert');
В итоге получаем быстрый и гибкий полнотекстовый поиск прямо внутри Postgres, без отдельных движков и костылей.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2
В софте очень часто работают так: система хранит текущее состояние.
Например:
» у пользователя такой баланс
» заказ сейчас в таком статусе
» подписка активна
Event Sourcing предлагает другой подход.
Идея простая:
хранить не финальное состояние, а всю историю изменений.
То есть вместо того, чтобы сохранять
ты сохраняешь события:
А текущий баланс считается путём воспроизведения этих событий.
По сути, как бухгалтерская книга.
Что такое событие в этом контексте?
Событие это факт, который уже произошёл и не меняется.
Например:
» PaymentReceived
» OrderConfirmed
» SubscriptionCancelled
События:
» не редактируются
» не удаляются
» только добавляются
Фактически база данных становится append-only.
Зачем вообще так усложнять?
Потому что это даёт мощные возможности из коробки:
» полная аудитируемость
» сквозная трассировка
» восстановление состояния на любой момент времени
» исторический дебаг: как мы вообще сюда пришли
Никаких дополнительных логов не нужно. История уже есть.
Но важно понимать: у этого подхода есть серьёзные trade-off-ы.
Event Sourcing усложняет всё остальное:
» чтобы читать текущее состояние, нужны проекции
» ментальная модель сложнее
» миграции событий - проблема и требуют аккуратности
Это сила в обмен на сложность.
Где Event Sourcing реально уместен?
Он хорошо заходит, когда:
» домен сложный
» нужна жёсткая аудитируемость
» события важнее состояния
» бизнес постоянно спрашивает «как мы к этому пришли»
Платежи, финансы, бухгалтерия, compliance — классические кандидаты.
Где его лучше не использовать?
» простые CRUD-системы
» тривиальная бизнес-логика
» команды без опыта работы с паттерном
» случаи, когда нужен только текущий стейт
Важное уточнение:
Event Sourcing не равен CQRS.
Их часто используют вместе, но одно не требует другого.
И напоследок главное.
Event Sourcing — это не оптимизация.
Это решение по моделированию.
Ты выбираешь смотреть на систему как на последовательность фактов, а не как на таблицу с изменяемыми значениями.
👉 @BackendPortal
Например:
» у пользователя такой баланс
» заказ сейчас в таком статусе
» подписка активна
Event Sourcing предлагает другой подход.
Идея простая:
хранить не финальное состояние, а всю историю изменений.
То есть вместо того, чтобы сохранять
balance = 100
ты сохраняешь события:
deposit +200
purchase -50
adjustment -50
А текущий баланс считается путём воспроизведения этих событий.
По сути, как бухгалтерская книга.
Что такое событие в этом контексте?
Событие это факт, который уже произошёл и не меняется.
Например:
» PaymentReceived
» OrderConfirmed
» SubscriptionCancelled
События:
» не редактируются
» не удаляются
» только добавляются
Фактически база данных становится append-only.
Зачем вообще так усложнять?
Потому что это даёт мощные возможности из коробки:
» полная аудитируемость
» сквозная трассировка
» восстановление состояния на любой момент времени
» исторический дебаг: как мы вообще сюда пришли
Никаких дополнительных логов не нужно. История уже есть.
Но важно понимать: у этого подхода есть серьёзные trade-off-ы.
Event Sourcing усложняет всё остальное:
» чтобы читать текущее состояние, нужны проекции
» ментальная модель сложнее
» миграции событий - проблема и требуют аккуратности
Это сила в обмен на сложность.
Где Event Sourcing реально уместен?
Он хорошо заходит, когда:
» домен сложный
» нужна жёсткая аудитируемость
» события важнее состояния
» бизнес постоянно спрашивает «как мы к этому пришли»
Платежи, финансы, бухгалтерия, compliance — классические кандидаты.
Где его лучше не использовать?
» простые CRUD-системы
» тривиальная бизнес-логика
» команды без опыта работы с паттерном
» случаи, когда нужен только текущий стейт
Важное уточнение:
Event Sourcing не равен CQRS.
Их часто используют вместе, но одно не требует другого.
И напоследок главное.
Event Sourcing — это не оптимизация.
Это решение по моделированию.
Ты выбираешь смотреть на систему как на последовательность фактов, а не как на таблицу с изменяемыми значениями.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4👍3🔥1
В SQLite около 155 800 строк кода, а тестовый набор - примерно 92 миллиона строк. Это примерно в 590 раз больше тестов, чем самого кода 🤯
Вот такой уровень тестирования нужен для настоящей продакшен-базы данных. Ниже — какие типы тестов у них есть.
» Тесты на нехватку памяти (OOM)
SQLite не может просто упасть, когда заканчивается память. На встраиваемых устройствах OOM — обычное дело. Они симулируют падения malloc в каждой возможной точке и проверяют, что база корректно это переживает.
» Тесты I/O-ошибок
Диски ломаются. Сеть отваливается. Права могут измениться посреди операции. SQLite подменяет файловую систему на кастомный слой, который может симулировать сбои после N операций, и проверяет, что данные не повреждаются.
» Краш-тесты
Что будет, если питание пропадёт посреди записи? Они симулируют крэш в случайные моменты во время записи, портят несинхронизированные данные, как это делает реальная файловая система, и проверяют, что транзакция либо полностью завершилась, либо чисто откатилась. Никакой порчи данных.
» Fuzz-тестирование
В SQLite кидают кривой SQL, битые файлы базы и случайный мусор. Инструмент dbsqlfuzz прогоняет около 500 миллионов мутаций тестов в день на 16 ядрах.
» 100% покрытие ветвлений
Каждая инструкция ветвления в ядре SQLite проверяется в обе стороны. Не просто «эта строка выполнялась», а «это условие было и true, и false».
Базы данных вообще не прощают ошибок :)
Если хочется копнуть глубже, советую почитать официальную документацию SQLite про их стратегию тестирования. Очень практично и по делу. А если понравился пост - ставь реакцию👌
👉 @BackendPortal
Вот такой уровень тестирования нужен для настоящей продакшен-базы данных. Ниже — какие типы тестов у них есть.
» Тесты на нехватку памяти (OOM)
SQLite не может просто упасть, когда заканчивается память. На встраиваемых устройствах OOM — обычное дело. Они симулируют падения malloc в каждой возможной точке и проверяют, что база корректно это переживает.
» Тесты I/O-ошибок
Диски ломаются. Сеть отваливается. Права могут измениться посреди операции. SQLite подменяет файловую систему на кастомный слой, который может симулировать сбои после N операций, и проверяет, что данные не повреждаются.
» Краш-тесты
Что будет, если питание пропадёт посреди записи? Они симулируют крэш в случайные моменты во время записи, портят несинхронизированные данные, как это делает реальная файловая система, и проверяют, что транзакция либо полностью завершилась, либо чисто откатилась. Никакой порчи данных.
» Fuzz-тестирование
В SQLite кидают кривой SQL, битые файлы базы и случайный мусор. Инструмент dbsqlfuzz прогоняет около 500 миллионов мутаций тестов в день на 16 ядрах.
» 100% покрытие ветвлений
Каждая инструкция ветвления в ядре SQLite проверяется в обе стороны. Не просто «эта строка выполнялась», а «это условие было и true, и false».
Базы данных вообще не прощают ошибок :)
Если хочется копнуть глубже, советую почитать официальную документацию SQLite про их стратегию тестирования. Очень практично и по делу. А если понравился пост - ставь реакцию
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12🤯7❤3
Два года назад парень сделал максимально простой демо-пример, который на уровне операционной системы показывает, что происходит, если не использовать пул соединений для Postgres.
С тех пор его рекомендуют даже LLM, и он регулярно получает такой фидбек:
«Впервые наглядно понял, как работает connection pooling».
Это и подтолкнуло поделиться этим видео с вами, друзья🎷 - смотреть
👉 @BackendPortal
С тех пор его рекомендуют даже LLM, и он регулярно получает такой фидбек:
«Впервые наглядно понял, как работает connection pooling».
Это и подтолкнуло поделиться этим видео с вами, друзья
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2
Media is too big
VIEW IN TELEGRAM
🎬 Что это? А это второй выпуск нового интерактивного шоу «АйТир Лист» от МойОфис
«АйТир Лист» – это шоу, в котором эксперты оценивают технологии, компании, фреймворки и ИТ-решения по шкале от 1 до 4. Каждый выпуск — это 14 табличек от модератора, жаркие дискуссии и итоговый рейтинг, который поможет зрителям разобраться в актуальных трендах и сделать собственные выводы.
Во втором выпуске мы оценим фичи и идиомы C++.
Гости выпуска:
— Данил Черепанов, архитектор Редакторов МойОфис
— Антон Полухин, эксперт-разработчик C++ Техплатформы Городских сервисов Яндекса
🎥 Смотрите наш юбилейный второй выпуск там, где вам удобно:
VK | YouTube | RuTube
Реклама
ООО "НОВЫЕ ОБЛАЧНЫЕ ТЕХНОЛОГИИ"
ИНН: 7703807270
erid: 2W5zFJ7ManC
«АйТир Лист» – это шоу, в котором эксперты оценивают технологии, компании, фреймворки и ИТ-решения по шкале от 1 до 4. Каждый выпуск — это 14 табличек от модератора, жаркие дискуссии и итоговый рейтинг, который поможет зрителям разобраться в актуальных трендах и сделать собственные выводы.
Во втором выпуске мы оценим фичи и идиомы C++.
Гости выпуска:
— Данил Черепанов, архитектор Редакторов МойОфис
— Антон Полухин, эксперт-разработчик C++ Техплатформы Городских сервисов Яндекса
🎥 Смотрите наш юбилейный второй выпуск там, где вам удобно:
VK | YouTube | RuTube
Реклама
ООО "НОВЫЕ ОБЛАЧНЫЕ ТЕХНОЛОГИИ"
ИНН: 7703807270
erid: 2W5zFJ7ManC
🔥2🤔2💊2
This media is not supported in your browser
VIEW IN TELEGRAM
Элегантное разделение ответственности в Apache Kafka даёт кучу возможностей для масштабирования.
Но за это приходится платить компромиссами.
Производитель, потребитель и брокер.
👉 @BackendPortal
Но за это приходится платить компромиссами.
Производитель, потребитель и брокер.
Please open Telegram to view this post
VIEW IN TELEGRAM
Привыкнув к визуальным редакторам вроде VS Code, каждый раз после SSH-подключения к серверу и необходимости править конфиги через Vim не хочется
На GitHub нашёл проект Fresh. Он переносит привычный графический опыт редакторов прямо в терминал.
Поддерживает работу мышью, прокрутку и стандартные хоткеи. Открыл и сразу работаешь, без заучивания команд.
При этом спокойно открывает файлы размером в несколько гигабайт, а потребление памяти практически незаметно.
👉 @BackendPortal
На GitHub нашёл проект Fresh. Он переносит привычный графический опыт редакторов прямо в терминал.
Поддерживает работу мышью, прокрутку и стандартные хоткеи. Открыл и сразу работаешь, без заучивания команд.
При этом спокойно открывает файлы размером в несколько гигабайт, а потребление памяти практически незаметно.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5👍2💊1
Сервер для потоковой трансляции видео, написанный на Go.
GitHub: https://github.com/gwuhaolin/livego/
👉 @BackendPortal
GitHub: https://github.com/gwuhaolin/livego/
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6😁4
Биллинговое решение для хостинг-компаний.
GitHub: https://github.com/Paymenter/Paymenter/
👉 @BackendPortal
GitHub: https://github.com/Paymenter/Paymenter/
Please open Telegram to view this post
VIEW IN TELEGRAM
Потоковая передача музыки с YouTube с фоновым воспроизведением и кэшированием.
https://github.com/25huizengek1/ViTune/
👉 @BackendPortal
https://github.com/25huizengek1/ViTune/
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5👍1
Только что открыл для себя Resend Go SDK — пожалуй, самый чистый и удобный способ отправлять письма из Go-приложений.
Простой и понятный API
Строгая типизация, нативная поддержка Go
Встроенная поддержка шаблонов
Массовая отправка писем
Webhooks и трекинг доставляемости
Отлично подходит для транзакционных писем, уведомлений и не только. Больше не нужно возиться с настройками SMTP.
Заценить можно тут❤️
👉 @BackendPortal
Простой и понятный API
Строгая типизация, нативная поддержка Go
Встроенная поддержка шаблонов
Массовая отправка писем
Webhooks и трекинг доставляемости
Отлично подходит для транзакционных писем, уведомлений и не только. Больше не нужно возиться с настройками SMTP.
Заценить можно тут
Please open Telegram to view this post
VIEW IN TELEGRAM
GitHub
GitHub - resend/resend-go: Resend's Official Go SDK
Resend's Official Go SDK. Contribute to resend/resend-go development by creating an account on GitHub.
1
Разверните свою облачную среду за несколько минут: виртуальные машины, S3-совместимое хранилище, Managed Kubernetes, базы данных.
▪️Быстрый старт, прозрачный биллинг, российские дата-центры.
▪️Удобные интерфейсы управления: веб-консоль, CLI, API, Terraform.
▪️Собственная разработка: развиваем облако так, как нужно пользователям, а не ждём решений от вендоров.
Развивайте свои IT-продукты. Об инфраструктуре позаботится облако.
Попробуйте MWS Cloud Platform бесплатно с грантом для новых пользователей.
▪️Быстрый старт, прозрачный биллинг, российские дата-центры.
▪️Удобные интерфейсы управления: веб-консоль, CLI, API, Terraform.
▪️Собственная разработка: развиваем облако так, как нужно пользователям, а не ждём решений от вендоров.
Развивайте свои IT-продукты. Об инфраструктуре позаботится облако.
Попробуйте MWS Cloud Platform бесплатно с грантом для новых пользователей.
👍1
freeCodeCamp только что запустили бесплатную интерактивную программу, где можно изучить SQL и реляционные базы данных, а затем получить верифицированный сертификат для LinkedIn.
В курсе разобраны все ключевые темы. Практику можно делать в своем локальном редакторе кода, после чего пройти финальный экзамен.
Полный анонс и подробный FAQ здесь
👉 @BackendPortal
В курсе разобраны все ключевые темы. Практику можно делать в своем локальном редакторе кода, после чего пройти финальный экзамен.
Полный анонс и подробный FAQ здесь
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3
This media is not supported in your browser
VIEW IN TELEGRAM
Превратите любой репозиторий GitHub в богатую, удобную для навигации документацию.
Просто замените «github» на «deepwiki» в URL-адресе репозитория.
👉 @BackendPortal
Просто замените «github» на «deepwiki» в URL-адресе репозитория.
Please open Telegram to view this post
VIEW IN TELEGRAM