Задать вопрос
  • Как работать с подключениями к БД в долгоживущих приложениях с EntityManager в RoadRunner?

    Тут нам надо просто подойти логически к вопросу. Понимаем, что RoadRunner держит приложение Symfony в памяти. Значит, в памяти будет находиться и сервис-контейнер со всеми инициализированными сервисами. Поэтому дефолтное подключение для Doctrine не подойдёт, потому что соединение упадёт, и оно будет выдавать ошибку.

    Т.е. нам надо написать свою обёртку вокруг доктриновского класса, предоставляющего соединение с базой данных. И в этой обёртке мы и сделаем логику псевдо-пула соединений. А именно, перед каждым запросом будем пинговать соединение, и если оно мертво, то пробовать реконнектиться и продолжать запросы далее в случае успешного реконнекта. Это самое простое, но не самое эффективное решение.

    1. Надеюсь, у вас уже установлен бандл для работы с Roadrunner

    composer require spiral/roadrunner-bundle

    2. Создаём вот эту вот обёртку над соединением

    <?php
    // src/DBAL/ConnectionWrapper.php
    
    namespace App\DBAL;
    
    use Doctrine\DBAL\Connection;
    use Doctrine\DBAL\Driver;
    use Doctrine\DBAL\Configuration;
    use Doctrine\Common\EventManager;
    
    class ConnectionWrapper extends Connection
    {
        /**
         * @var int
         */
        private $reconnectAttempts = 3;
    
        public function __construct(array $params, Driver $driver, ?Configuration $config = null, ?EventManager $eventManager = null)
        {
            parent::__construct($params, $driver, $config, $eventManager);
        }
    
        public function prepare($sql)
        {
            $this->ping();
            return parent::prepare($sql);
        }
    
        public function executeQuery(string $sql, array $params = [], $types = [], ?QueryCacheProfile $qcp = null)
        {
            $this->ping();
            return parent::executeQuery($sql, $params, $types, $qcp);
        }
    
        public function executeUpdate(string $sql, array $params = [], array $types = [])
        {
            $this->ping();
            return parent::executeUpdate($sql, $params, $types);
        }
    
        public function ping(): bool
        {
            if ($this->isConnected() && $this->getWrappedConnection()->ping()) {
                return true;
            }
    
            $this->close();
    
            for ($i = 0; $i < $this->reconnectAttempts; $i++) {
                try {
                    $this->connect();
                    if ($this->getWrappedConnection()->ping()) {
                        return true;
                    }
                } catch (\Exception $e) {
                    // ещё разок
                }
            }
    
            throw new \RuntimeException("Unable to reconnect to the database.");
        }
    }


    3. Конфигурируем Доктрину, чтобы использовала нашу обёртку.

    # config/packages/doctrine.yaml
    doctrine:
        dbal:
            # обычные настройки
            url: '%env(resolve:DATABASE_URL)%'
            driver: 'pdo_mysql'
            server_version: '8.0'
            charset: utf8mb4
            default_table_options:
                charset: utf8mb4
                collate: utf8mb4_unicode_ci
    
            # наша обёртка
            wrapper_class: App\DBAL\ConnectionWrapper


    4. Что ещё

    • Обязательно очищайте EntityManager вручную после каждого запроса по API, или каждого большого действия, или что там у вас ещё. Иначе доктриновская Identity Map распухнет, и память будет течь как мороженное в пустыне.
    • Не забывайте аккуратно обращаться с транзакциями и всегда их коммитить или откатывать.
    • Продумайте, как лучше всего рестартовать сервис, если реконнект всё-таки не сработает.


    5. Лучше, конечно, сделать всё через воркеры RoadRunner.

    Это сложнее, но более правильно, если так можно выразиться. Тут уже сами разберитесь в документации к этим вот пакетам, там нужно повозиться.

    composer require spiral/roadrunner-symfony
    composer require spiral/roadrunner-doctrine


    Но идея та же, нужно написать обёртку для Доктрины, плюс использовать воркер RoadRunner. Там будет уже более адекватный connection pool и т.д.
    Ответ написан
    Комментировать
  • Как в Yii2 сделать логирование в файлы и их архивирование?

    webinar
    @webinar Куратор тега Yii
    Учим yii: https://youtu.be/-WRMlGHLgRg
    Логирование можно настроить как угодно, вот гайд:
    https://www.yiiframework.com/doc/guide/2.0/en/runt...
    Можно выбрать место куда будут падать ваши логи. А вот архивирование - это уже кроном. Запускаете допустим раз в день, берете из указанного места, архивируете, удаляете старое и т.д.
    Ответ написан
    2 комментария
  • Упаковка Angular или Vue в один файл для использования на стороннем сайте?

    kulakoff
    @kulakoff Куратор тега Vue.js
    Vue.js developing
    Можете сделать например так:
    в своем скрипте создать глобальный объект и сделать функцию инициализации, которая создаст экземпляр vue и привяжет к соответствующему элементу на сайте.

    В общих чертах как-то так:

    на сайте:

    <script src="path_to_script"></script>
    <script type="text/javascript">
       var vm;
       vm = vuecomp.init("vuecomponent", {
                // some options
       });
    </script>
    
    <div id="vuecomponent"></div>


    в своем скрипте в точке входа:

    import Vue from 'vue'
    
    // ...
    
    const vuecomp =  {
      init(elementId, options) {
                return new Vue({
                  el: `#${elementId}`,
                  // ...
                })
      }
    }
    
    export default vuecomp

    И собираем библиотеку используя webpack например.
    Ответ написан
    Комментировать