Как стать автором
Поиск
Написать публикацию
Обновить

Бэкенд

Сначала показывать
Порог рейтинга

Магические квадраты с произведением

 О магических квадратах известно, наверное, всё. А возможны ли магические квадраты, в которых равны не суммы значений в строках, столбцах и на диагоналях, а их произведения? Оказывается – возможны. В дальнейшем буду называть такие квадраты «магическими квадратами с произведением» (сокращённо – МКП).

Интересно, что, как и «обычных» магических квадратов, возможно бесчисленное множество вариантов МКП. В общем случае для трёх чисел a, b и n МКП размером 3 × 3 имеют вид:

При этом ab, a ≠ 1, b ≠ 1, ab2, ba2,

Интересно, что любой МКП размером 3 × 3 может быть основой для формирования бóльших МКП. Одно из возможных решений заключается в том, чтобы поместить такой  квадрат в центр квадрата 5 × 5 и потом подобрать такие остальные числа, чтобы они соответствовали свойствам МКП. Это означает, что МКП являются также так называемыми «рамочными магическими квадратами» – магическими квадратами, которые сохраняют свое магическое свойство, если в них отбросить окаймляющие «полосы» в две клетки.

После комментариев  @miksoft я удалю сей свой пост

Теги:
Рейтинг0
Комментарии6

Работаем с событиями без плагина или как перехватить редирект в Joomla 5

В расширении быстрого заказа для JoomShopping. Я создаю экземпляр модели Checkout и вызываю метод checkStep().

$checkoutModel = JSFactory::getModel('checkout', 'Site');
$checkoutModel->checkStep(2);

В методе checkStep есть условия, при выполнении которых происходит установка сообщения и редирект.

if (!$check)
{
    JSError::raiseNotice('', 'Message');
    $mainframe->redirect('Url');
    exit();
}

Но мне надо получить результат метода checkStep или исключение. И продолжить работу.

Смотрим какое событие вызывается при редиректе — ApplicationEvents::BEFORE_RESPOND.

Подписываться на события могут не только плагины, но и любые другие callable объекты.

Создадим функцию которая получает заголовки редиректа, удаляет их и бросает исключение:

$onApplicationBeforeRespond = function()
{
	$app = Factory::getApplication();
	$response = $app->getResponse();
	$status = $response->getHeader('Status');
	$location = $response->getHeader('Location');
	$response = $response->withoutHeader('Status');
	$response = $response->withoutHeader('Location');
	$app->setResponse($response);

	throw new RedirectCaughtException($status[0], $location[0]);
};

Перед вызовом $checkoutModel->checkStep(2); подпишем нашу функцию на прослушивание события, а после отпишем. И обернём вызов в try/catch.

$dispatcher->addListener(
	ApplicationEvents::BEFORE_RESPOND,
	$onApplicationBeforeRespond
);

try
{
	$checkoutModel->checkStep(2);
}
catch (RedirectCaughtException $e)
{
    // Обрабатываем исключение
}

$dispatcher->removeListener(
	ApplicationEvents::BEFORE_RESPOND,
	$onApplicationBeforeRespond
);

Таким образом мы можем перехватывать редиректы внутри блока try.

Теги:
Всего голосов 1: ↑1 и ↓0+1
Комментарии0

Как выбрать курс по Kubernetes? Roadmap для тех, кто ещё не разобрался

На нашем факультете Kubernetes есть целых шесть курсов, разработанных под разные потребности. Мы подготовили роадмап, который поможет разобраться в них и сделать правильный выбор.

Какой курс подойдёт именно вам? Давайте разбираться!

1. Kubernetes База

Курс для инженеров и администраторов, которые только знакомятся с k8s. Учим базовым вещам: компоненты, абстракции, настройка кластера и работа с ним.

2. Kubernetes для разработчиков

Продвинутый курс с акцентом на разработку. Научим разрабатывать приложение под k8s и запускать его в кластере.

3. Kubernetes Мега

Большой продвинутый курс для инженеров, которые уже работали с k8s (или прошли базовый курс). Разбираем в теории и на практике тонкости конфигурации и установки production-ready кластера.

4. Service mesh

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

5. Безопасность в Kubernetes

Видеокурс. Подойдёт всем, кто так или иначе касается безопасности проекта — ИБ, DevOps, SRE и разработчикам, самостоятельно работающим с k8s.

6. Мониторинг и логирование в Kubernetes

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

А чем ещё можно дополнить стек?

1. Docker для админов и разработчиков

Видеокурс. Начнём с основ, и уже через три недели вы сможете запускать приложения в Docker и работать с образами на продвинутом уровне.

2. Gitlab CI/CD

Видеокурс. Расскажем про принципы работы CI/CD, научим автоматизировать процесс интеграции и поставки и ускорять цикл разработки с минимальными рисками.

3. CI/CD c Jenkins

Видеокурс. Поможем пройти путь от настройки первого плагина и создания простого пайплайна до Jenkins as code и внедрения в Kubernetes.

Теги:
Рейтинг0
Комментарии0

3 ключевые метрики, которые спасут микросервисный проект

Современные системы — это сложные экосистемы, где каждая ошибка может стоить бизнесу денег и репутации. Рассказываем, какие метрики нельзя игнорировать, чтобы не пропустить критичные сбои.

Инфраструктурные метрики

Базовые показатели вроде CPU и RAM уже не спасают. Для микросервисов важнее:

Статус подов в Kubernetes:

  • Количество рестартов.

  • Фейлы readiness/liveness проб.

  • Используйте метрику kube_pod_status_ready в Prometheus, чтобы находить «битые» поды.

Трассировка запросов: время выполнения каждого этапа через Jaeger.

Пример: Если поды перезапускаются чаще 5 раз в час — это сигнал к немедленной проверке.

Бизнес-метрики

Инфраструктура может быть идеальной, но если падает конверсия — бизнес теряет клиентов. Отслеживайте:

  • Конверсию платежей (например, от корзины к оплате).

  • Время обработки заказов.

Код для .NET-сервиса:

using App.Metrics;

public class PaymentService {
    private readonly IMetrics _metrics;
    public PaymentService(IMetrics metrics) => _metrics = metrics;
    
    public void ProcessPayment() {
        try {
            // Логика платежа...
            _metrics.Measure.Counter.Increment(MetricsRegistry.PaymentSuccessCounter);
        } 
        catch {
            _metrics.Measure.Counter.Increment(MetricsRegistry.PaymentFailedCounter);
        }
    }
}

Эти метрики интегрируются в Grafana, чтобы вы видели, как каждая транзакция влияет на бизнес.

Пользовательский опыт

Даже 1 секунда задержки может увеличить отток пользователей на 7%. Контролируйте:

  • Время отклика API (p95, p99).

  • Частоту ошибок 5xx/4xx.

  • Структурированные логи с контекстом:

{
  "timestamp": "2023-10-05T12:34:56Z",
  "level": "ERROR",
  "userId": "a1b2c3",
  "operation": "process_payment",
  "message": "Failed to charge card: insufficient funds"
}

Теги вроде userId помогают быстро найти все связанные с ошибкой события.

Теги:
Рейтинг0
Комментарии0

«Криптонит» приглашает на Spark-митап в Москве 29 мая!

Приглашаем на наш Spark-митап: обсудим кейсы, практики применения и тренды развития!

Когда и где пройдёт?
29 мая в 18:30 в Музее криптографии (https://cryptography-museum.ru/)

Кому Spark Meetup полезен?

  • инженерам данных и аналитикам данных

  • программистам со знанием Spark и Scala

  • всем смежным специальностям из телекома, банков, промышленности и ретейла

Кто будет выступать с докладами?
Эксперты из «Криптонита», Positive Technologies и М2. Программу можно посмотреть тут — https://clc.to/SparkMeetup

Как зарегистрироваться?
Вот по этой ссылке — https://clc.to/SparkMeetup

Будет ли трансляция?
Обязательно будет. Ссылку разместим позже на странице мероприятия — поэтому советуем зарегистрироваться на оффлайн-встречу, даже если вы не сможете прийти. Так вы точно не потеряете ссылку на онлайн

Нужно что-то платить?
Нет, митап бесплатный — ждём всех неравнодушных к программированию на Spark!

Зарегистрироваться — https://clc.to/SparkMeetup

Теги:
Всего голосов 2: ↑2 и ↓0+2
Комментарии0

Ваши приложения в безопасности? Давайте проверим!

Пока мы готовимся к интенсиву по DevSecOps, предлагаем вам пройти короткую самодиагностику и проверить, насколько безопасны ваши подходы к разработке.

Мы создали тест из 5 коротких вопросов и положили его в бота. Пройдите его и найдите слабые места раньше, чем это сделают другие.

А ещё в боте есть чек-лист по DevSecOps и карта зрелости и приоритетов — забрать их можно бесплатно.

Перейти в бота

Теги:
Рейтинг0
Комментарии0

Порождающие паттерны: какие они и в чем их назначение?

В новой серии третьего сезона курса «Паттерны и практики написания кода» перейдём от теории к практике и погрузимся в мир прикладных паттернов. В предыдущем видео мы узнали, что паттерны делятся на три группы: сегодня вместе с бэкенд-инженером Юрой Афанасьевым начнём рассматривать первую из них — порождающие паттерны

Смотреть VK
Смотреть YouTube

Подписывайтесь на канал AvitoTech в Telegram, там мы рассказываем больше о профессиональном опыте наших инженеров, проектах и работе в Авито, а также анонсируем митапы и статьи.

Теги:
Всего голосов 27: ↑26 и ↓1+25
Комментарии0

Посмотрите на код ниже — где в нём проблема? Пишите ваши мысли в комментариях, а ниже мы дадим решение ошибки.

object UnitError {

def printMsg(message: String): Unit = {
 println(message)
 }

def process(data: List[Int]): List[Unit] = {
 for (element <- data) yield {
 printMsg(s"Элемент: $element")
 }
 }

def main(args: Array[String]): Unit = {
 val nums = List(1, 2, 3)
 val res = process(nums)
 println(s"Результат: $res") // Вывод List[Unit] даёт неожиданный результат
 }
 }

Дальше будет решение — если не хотите спойлеров, пролистните текст ниже.

Ошибка заключается в неверной конструкции при использовании функции process. Она возвращает пустые значения: List((), (), ()). Происходит это потому, что yield собирает результаты каждой итерации. В итоге получается список, состоящий из пустых значений Unit — по одному на каждый элемент в data.

Unit в Scala — это аналог void в Java и Си-подобных языках, означающий пустое значение. В данном примере yield собирает результаты printMsg(...), которые все являются Unit (пустыми).

Программисты, привыкшие к императивным языкам и переходящие на Scala, интуитивно ожидают, что такая конструкция будет возвращать какие-то преобразованные данные, например — как это делает map в JavaScript. То есть, начинающие скалисты могут ожидать здесь на выходе список элементов, а получат пустой вывод.

Исправление

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

def printMsg(message: String): String = { // Теперь возвращает String
 println(message)
 message // Возвращает саму строку
 }

def process(data: List[Int]): List[String] = { // Теперь функция возвращает List[String]
 for {
 element <- data
 } yield {
 printMsg(s"Обрабатываем элемент: $element") // Теперь выводится результат String
 }
 }
Теги:
Рейтинг0
Комментарии1

Траблшутинг в k8s: инструменты и лайфхаки для разработчиков

➡️ бесплатный вебинар завтра в 19:00.

Что будем обсуждать:

- начнём с kubectl,

- посмотрим сайдкар контейнеры и узнаем, зачем их использовать,

- разберёмся с сетевыми проблемами, 

- научимся использовать strace для сложных случаев.

Будет полезно, даже если ваши сервисы крутятся на bare metal или VM без намёка на оркестрацию.

Спикер: Виталий Лихачев, SRE в крупном нидерландском тревелтехе

Ведущий: Кирилл Борисов, SRE в VK

Когда: 14 мая в 19:00 мск

Занять место на вебинаре — через бота.

Теги:
Рейтинг0
Комментарии0

Привет, Хабр. Подготовили подборку бесплатных открытых уроков от Otus, которые пройдут на этой неделе. Опытные практики проводят вебинары в живом формате, что позволит не только освоить новые знания, но и задать вопросы экспертам. Зарегистрируйтесь и присоединяйтесь!

Вторник, 13 мая:

Среда, 14 мая:

Четверг, 15 мая:

Понедельник, 19 мая:

Список всех открытых уроков по всем ИТ-направлениям можно посмотреть в календаре.

Теги:
Всего голосов 3: ↑3 и ↓0+3
Комментарии0

Свой класс события для плагинов Joomla. Продолжение.

Продолжение потому, что начало уже было в статье Виталия Некрасова на Хабре.

Кратко.

В Joomla 5+ для событий аргументы упаковываются в собственные классы событий: ContentPrepareEvent, AfterSaveEvent и т.д. Данные из них мы получаем в виде $event->getArgument('argument_name') или [$var, $var2] = array_values($event->getArguments());. Также для разных типов событий могут быть специфичные методы типа $article = $event->getItem(); в ContentPrepareEvent и т.д. И в статье Виталия как раз об этом рассказывается.

А так же рассказывается о методах onGet и onSet. В ядре Joomla в классе \Joomla\CMS\Event\AbstractEvent сказано:

/**
   * Add argument to event.
   * It will use a pre-processing method if one exists. The method has the signature:
   *
   * onSet($value): mixed
   *
   * where:
   *
   * $value  is the value being set by the user
   * It returns the value to return to set in the $arguments array of the event.
   *
   * @param   string  $name   Argument name.
   * @param   mixed   $value  Value.
   *
   * @return  $this
   *
   * @since   4.0.0
   */

Добрался я тоже до своего класса события для плагинов, порылся в ядре и подумал, что onSet... и onGet... методы не обязательно делать (хотя в статье по ссылке об этом не упоминается). Это методы для "предварительных проверок и манипуляций" с данными перед тем, как они будут отданы через getArgument() или get<ArgumentName>. Метод getData() отдаст данные, которые предварительно будут обработаны методом onGetData(). Но обработаны они будут только в том случае, если метод реализован. Если нет, то ничего страшного. Ошибки не будет.😎

Эти методы напоминают своеобразные плагины внутри плагинов. На мой взгляд излишнее усложнение, хотя сеттеры и геттеры должны заниматься по идее только сеттерством и геттерством, а проверку/ приведение типов можно отдать в методы onSet... / onGet....

Теги:
Всего голосов 2: ↑2 и ↓0+2
Комментарии0

Новый тайпчекер для Python от авторов ruff и uv, написанный на Rust

Вышло видео про новый тайпчекер и lsp: ty (старое название red-knot) от авторов ruff и uv. Пока по первым впечатлениям – бомба! Не смотря на версию 0.0.0a8 🌚

Из плюсов:

  • Быстрый

  • На расте

  • Куча новых фичей для типов

  • Полная спецификация

  • Интеграция с ruff и IDEшками

Из минусов:

  • Пока есть баги (но их поправят, конечно же)

  • Нет плагинов (и скорее всего никогда не будет)

  • Софт от молодой и маленькой компании

  • Как сделать поддержку ty и mypy вместе? А если использовались ty_extensions?

Обсуждение: а как вам проект? Успели попробовать?

Теги:
Всего голосов 8: ↑8 и ↓0+10
Комментарии1

GIN индексы в PostgreSQL

Сегодня хочу рассказать о GIN индексах в PostgreSQL. Это один из мощных инструментов, которые есть в БД PostgreSQL. Но почему-то очень многие незаслуженно обходят его стороной.

Что такое GIN индекс

GIN (Generalized Inverted Index) – это инвертированный индекс, который предназначен для ускорения поиска в структурах данных, содержащих составные типы. Он имеет встроенную оптимизацию, позволяющую искать по элементам внутри сложных структур. По своей сути, это обратный индекс, где для каждого уникального элемента хранится список указателей на записи, в которых он встречается. Это дает возможность быстро находить записи, соответствующие запросу.

Для каких типов данных используется GIN индексы

GIN-индексы особенно эффективны для следующих типов данных:

  • Массивы

    • Хранение списков значений

    • Быстрый поиск по элементам массива

    • Пример: теги, категории, списки ID

  • JSONB

    • Хранение полуструктурированных данных

    • Быстрый поиск по ключам и значениям

    • Поддержка сложных запросов к JSON-документам

  • Полнотекстовый поиск

    • Индексация текстовых полей

    • Быстрый поиск по словам и фразам

    • Поддержка различных языков

Преимущества GIN индексов

  • Эффективность поиска по структурам данных: Хорошо подходит для обработки массивов и структурированных данных типа JSONB. Позволяет быстро находить нужные строки даже среди миллионов записей. Хранит только уникальные элементы и их местоположение, вследствии этого более экономный по сравнению с полным сканированием.

  • Поддержка различных типов данных: Работает с различными типами - строки, числа, массивы, объекты JSONB и даже геопространственные данные.

  • Подходит для оптимизации полнотекстового поиска: Улучшает производительность запросов с использованием операторов @@ и функций вроде to_tsvector() и to_tsquery(). Особенно полезен там, где требуются операции пересечения (&&), включения (@>), проверки существования элементов массива (?, ?&) и другие специфические условия.

Недостатки GIN индексов

  • Обновление: Каждый раз, когда изменяется запись, содержащая поля, входящих в GIN индекс, индекс обновляется целиком. Это увеличивает нагрузку на систему при частых изменениях данных.

  • Больший размер: GIN индекс занимает больше места на диске по сравнению с традиционными B-tree индексами, так как хранит список всех значений, содержащихся в колонке.

  • Низкая производительность на малых объемах данных: При небольших объемах данных GIN индекс может быть менее эффективным.

  • Сортировка:: По умолчанию не поддерживает эффективные запросы с сортировкой. Стоит учитывать при разработке, можно использовать решения в комбинации с другими индексами.

Заключение

При работе с массивами, JSONB полями и полнотекстовым поиском стоит рассмотреть использование GIN индексов для данных полей. Это позволит повысить эффективность и производительность БД PostgreSQL. Но, в то же время, стоит учитывать особенности его обслуживания и требования к системе. Очень аккуратно применять к часто изменяемым данным.
Очень хорошая статья о GIN индексах https://habr.com/ru/companies/postgrespro/articles/340978/

Более подробно с примерами у меня в телеграмм

Спасибо за внимание!

Теги:
Всего голосов 1: ↑0 и ↓1-1
Комментарии3

Ближайшие события

Анимация AWS сервисов ✨ 🎉

Парни из AWS Fundamentals запилили каталог AWS анимаций. В настоящее время он включает в себя 14 сервисов и паттернов, но, ожидается, что команда будет добавлять новые еженедельно!

В текущем каталоге:

  • The Dark Reader Deployment Pattern

  • Polling vs. WebSockets via Amazon API Gateway

  • Running Code on the Edge with CloudFront

  • Adaptive Capacity with DynamoDB

  • Bidirectional Sync across Regions with DynamoDB Global Tables

  • Async vs. Synchronous Invocations at AWS Lambda

  • What’s Happening at a Cold Start in AWS Lambda?

  • DNS Resolution with Route 53

  • Region Failovers with Route 53 DNS Records

  • Multi-Region Routing with Route 53 Latency Records

  • Lifecycle Policies at Amazon S3

  • Long vs. Short Polling with Amazon SQS

  • How Are You Charged at AWS Step Functions?

  • VPC Gateway Endpoints

Каталог смотреть тут: https://awsfundamentals.com/animations

Теги:
Рейтинг0
Комментарии0

Рэймонд Чен — ветеран компьютерной индустрии, который работает в Microsoft c 1992 года. Рэймонд участвовал в разработке OS/2, Windows 95, DirectX и оболочки Windows, а последние десятилетия отвечает за сохранение обратной совместимости системы. В своём блоге Old New Thing Чен регулярно делится забавными историями из разработки софта, но также показывает действительно полезные примеры.

На этот раз Чен показал, почему история буфера обмена не отражает быстрые изменения содержимого буфера. Рэймонд приводит следующий фрагмент кода от клиента. Этот код был написан для некой утилиты, вставляющей в историю буфера обмена объекты. В некотором роде историю прошлых изменений превращали в будущее — целью было предугадать, какие элементы пользователь хотел бы видеть в истории буфера обмена.

// В целях наглядности вся проверка ошибок опущена
#include <windows.h>

void SetClipboardText(HWND hwnd, PCWSTR text)
{
    OpenClipboard(hwnd);
    EmptyClipboard();
    auto size = sizeof(wchar_t) * (1 + wcslen(text));
    auto clipData = GlobalAlloc(GMEM_MOVEABLE, size);
    auto buffer = (LPWSTR)GlobalLock(clipData);
    strcpy_s(buffer, size, text);
    GlobalUnlock(clipData);
    SetClipboardData(CF_UNICODETEXT, clipData);
    CloseClipboard();
}

// Чтобы они были под рукой, разместим эти строки в истории буфера обмена
static constexpr PCWSTR messages[] = {
    L"314159", // номер бага, который мы хотим исправить
    L"e83c5163316f89bfbde7d9ab23ca2e25604af290", // коммит, к которому привязываем ошибку
    L"Widget polarity was set incorrectly.", // комментарий, который нужно добавить
};

int wmain([[maybe_unused]] int argc,
          [[maybe_unused]] wchar_t* argv[])
{
    auto tempWindow = CreateWindowExW(0, L"static", nullptr, WS_POPUPWINDOW,
            0, 0, 0, 0, nullptr, nullptr, nullptr, nullptr);

    for (auto message : messages)
    {
        SetClipboardText(tempWindow, message);
    }
    DestroyWindow(tempWindow);
    return 0;
}

Код записывает в буфер обмена последовательно три строковые переменные. Однако при запуске утилиты в истории буфера обмена оказывалась лишь одна — последняя. Куда делись две остальные?

Дело в том, что служба истории буфера обмена работает асинхронно через механизм Clipboard Format Listener, существующий с эпохи Windows Vista. В этом механизме через функцию Add­Clipboard­Format­Listener приложение добавляет себя в качестве листенера. После этого никаких дополнительных опросов буфера обмена проводить не нужно — система сама оповестит приложение, если буфер изменился.

При получении уведомления служба истории буфера обновляет собственно историю буфера обмена. Но из-за асинхронности событие может происходить с задержкой. Как объясняет Чен, из-за асинхронной природы обновлений при получении WM_CLIPBOARD­UPDATE от Clipboard Format Listener буфер может успеть обновиться ещё раз.

Как считает Рэймонд, это даже не баг, а фича. Так получается избегать приложений, которые быстро спамили бы в буфер обмена множество изменений. Если даже пользователь не успевает воспользоваться содержимым буфера, то сохранять это для истории смысла нет, указывает Чен.

В другом посте из своего блога Рэймонд объяснил механизмы утилит-просмотрщиков буфера обмена с синхронными обновлениями буфера. Здесь периодически выполняется опрос GetClipboardSequenceNumber. У данного подхода тоже есть проблемы: редкий опрос угрожает привести к пропуску изменения буфера, но слишком частые запросы создадут лишнюю нагрузку на систему.

Рэймонд обещает в следующий раз показать, как исправить код выше.

Теги:
Всего голосов 5: ↑4 и ↓1+6
Комментарии0

Как правильно работать с паттернами кода?

Всем привет! Это третий сезон курса «Паттерны и практики написания кода». Первая серия вводная: в ней бэкенд-инженер Юра Афанасьев знакомит вас с историей паттернов и их функциями, а также рассказывает, как с ними правильно работать.

Смотреть VK
Смотреть YouTube

Подписывайтесь на канал AvitoTech в Telegram, там мы рассказываем больше о профессиональном опыте наших инженеров, проектах и работе в Авито, а также анонсируем митапы и статьи.

Теги:
Всего голосов 29: ↑29 и ↓0+29
Комментарии0

Довелось мне в последнее время поглядеть на "современные" проекты на Kotlin, и я признаюсь был поражен повсеместным использованием корутин в коде. Используют их просто везде: для обработки входящих соединений, для запросов в базы данных, для вызова внешних API, для операций с файлами на сетевых файловых системах. Знаете, в языке есть слова-паразиты — так вот кажется мне что в Kotlin корутины — это паттерн-паразит. Кажется корутины — это как магические заклинания, которые волшебным образом запустят код "где-то там, в локальном облаке".

Каждый раз когда я сталкиваюсь с туториалами про корутины — самым первым примером идёт конечно sleep на 10 тысяч "потоков". Притом как вы понимаете, вызывать нужно специально подготовленный для этого sleep, а не настоящий Thread.sleep — потому что с ним никакой магии не получится. Это создаёт обманчивое впечатление будто бы любая блокирующая операция автоматически волшебным образом превращается в асинхронную, за бесплатно увеличивая пропускную способность приложения. Хотелось бы напомнить любителям корутин что это не так.

Никто за вас не перепишет обычное чтение из сокета/файлового дескриптора на асинхронные ввод-вывод с проверкой наличия байт для чтения во входящем потоке через Selector::select — чудес не бывает. И как бы вы не увеличивали kotlinx.coroutines.io.parallelism рано или поздно при безудержном использовании корутин пул потоков забьётся чем-нибудь медленным и ваше приложение просто встанет раком.

Для примера попросите чатжпт написать вам простейший echo socket server на корутинах. Ну и клиента, который попробует работать с этим сервером в 100 обычных потоков (не так уж и много для нормального продакшн бэкенда). Надеюсь для вас не будет сюрпризом то, что сервер будет обрабатывать только 64 первых счастливых клиентов, а к остальным доберётся только когда эти первые клиенты закроют соединения.

Теги:
Рейтинг0
Комментарии2

Кардинальное упрощение привязки GitHub, GitLab, Bitbucket в Amvera Cloud

Привязка репозиториев GitHub, GitLab, BitBucket вызывала у наших пользователей затруднения, и мы обещали упростить процесс.

Теперь для привязки репозитория достаточно указать токен и выбрать ветку и репозиторий.

Способ позволяет организовать максимально простой деплой и обновление приложений через git push. Для обновления приложения достаточно сделать коммит в привязанный репозиторий, и оно соберется и бесшовно запустится автоматически.

Заполняем три поля и CI/CD готов
Заполняем три поля и CI/CD готов

Подробная инструкция по подключению доступна по ссылке.

Amvera Cloud — это облако для простого деплоя приложений через git push (или интерфейс). Встроенный CI/CD, бэкапы и мониторинг позволяют развернуть проект тремя командами в IDE и не думать о настойке инфраструктуры. Amvera проще, чем использование VPS.

Теги:
Всего голосов 2: ↑1 и ↓1+1
Комментарии0

Магические шестиугольники. Обзор соревнования по программированию

Приветствую всех любителей спортивного программирования!

В данной статье рассмотрим интересный сайт для программистов - Al Zimmermann's Programming Contests.

На этой площадке проводится несколько соревнований в год. Каждое соревнование (контест) длится в среднем несколько месяцев. Задачи по своей формулировке не очень сложные. Но вот над решениями вам придётся изрядно потрудится.

Теги:
Рейтинг0
Комментарии0

Класс расширения (Extension) для компонентов Joomla 5

Перевод с английского: Joomla! Programmers Documentation for Joomla 5.2

В ряде случаев Joomla может взаимодействовать с нашим компонентом. Например:

  • Роутер Joomla может использовать роутер нашего компонента для анализа и создания ЧПУ-адресов;

  • Если наш компонент поддерживает категории, то com_categories будет отображать в представлении категорий сводку по каждой категории, содержащую количество материалов с этой категорией, с разбивкой по статусу публикации;

  • Если наш компонент поддерживает пользовательские поля, то com_fields будет вызывать метод getContexts(), чтобы получить типы материалов, к которым можно привязать пользовательские поля;

  • Если наш компонент поддерживает мультиязычные связи, то com_associations потребуется знать типы материалов, для которых возможны связи;

  • И, конечно же, Joomla потребуется запустить наш компонент, чтобы получить вывод.

Причины введения класса расширения становятся понятнее, если рассмотреть, как другие части кода Joomla взаимодействовали с нашим расширением в Joomla 3.

В Joomla 3 все эти части кода обращались к кодовой базе нашего компонента довольно хаотичным образом — вызывая функции из различных вспомогательных файлов.

А в Joomla 4 это упрощено:

Начиная с Joomla 4, другие компоненты получают доступ к нашему компоненту com_example, вызывая метод:

$extension = $app->bootComponent("com_example");

Затем они могут вызывать необходимые им методы через этот экземпляр класса расширения.

Справка:

Класс расширения (Extension) компонента вы можете найти в административной части компонента. Например, для компонента com_content это файл Root/administrator/components/com_content/src/Extension/ContentComponent.php, для com_exampleRoot/administrator/components/com_example/src/Extension/ExampleComponent.php

Сразу после создания экземпляра класса расширения компонента код библиотеки Joomla вызовет метод boot вашего класса расширения, передавая дочерний экземпляр Контейнера внедрения зависимостей (Dependency Injection Container):

$extension->boot($container);

По сути, это возможность делать буквально всё, что вам нужно. Например, метод иногда используется для настройки определённых классов, которые будут использоваться с вызовами HtmlHelper::_(). Или же можно сохранить ссылку на ваш дочерний DI-контейнер (который иначе может быть сложно получить).

После первого создания экземпляра вашего компонента Joomla кэширует этот экземпляр. При повторном вызове

$extension = $app->bootComponent("com_example");

Joomla просто возвращает существующий экземпляр вашего класса расширения, вместо повторного создания объекта и вызова метода boot(). Вы даже можете вызвать bootComponent, передав свой компонент, чтобы получить ссылку на свой собственный объект расширения.

Теги:
Всего голосов 1: ↑1 и ↓0+1
Комментарии0