Конвертирование Zend конфига из ini в yaml. Подводные камни

в 21:31, , рубрики: mysql, php, yaml, Zend Framework, метки: ,

В качестве предисловия скажу что мне всегда нравился yaml. Так сложилось что я по большей части работаю с Zend Framework Но к сожалению ZF долго не поддерживал yaml. Тогда я добавил простой класс который был оберткой для Symfony компонента sfYaml и начал по-тихоньку использовать yaml в своих проектах.

Наконец-то в ZF 1.11.12 добавил Zend_Config_Writer_Yaml и я решил переконвертировать конфиги из ini в yaml

Недолго думая, я нашел на просторах интернета готовый скрипт. Выглядел примерно так.

$inputfile = APPLICATION_PATH . '/configs/application.ini';
$outputfile = APPLICATION_PATH. '/configs/application.yml';
 
$config = new Zend_Config_Ini($inputfile, null, array('allowModifications' => false, 'skipExtends'=> true));
$writer = new Zend_Config_Writer_Yaml();
$writer->write($outputfile, $config, true, true);

Такс, используются только ZF классы, никакой самодеятельности — уже хорошо. Попробывал переконвертировать. Получилось все как надо. Запустил тесты — все работает. Хорошо, теперь сделаем тоже самое на боевом сервере.

Через некоторое время мы стали получать ошибку от mysql General error: 1205 Lock wait timeout exceeded; Я пробую выполнить просто запрос и напарываюсь на лок. Хорошо смотрим SHOW PROCESSLIST и ничего не видим. Нужно отметить что пробема касалось только InnoDB таблиц, а 90-95% у нас MyISAM. Погуглил немного по этому поводу — пробуем делать show engine innodb status. Вижу только not started threads т.е. нет транзакции запущенной, которая могла бы лочить другие запросы.
Пробую дернуть админов — ничего ценого от них не узнал. Предложили добавить индексы… ну епрст.

Ладно, надо же что то делать. Мы не так давно начали импользовать Gearman — соответственно есть воркеры, которые по сути являются демонами и открывают долгие коннекты. Начал грешить на них — дай думай перезапущу их. И помогло лок снялся. Но причина то все равно не ясна. Добавил принутильный коммит после выполнения каждой задачи — вроде все тихо.

На следующий день проверяю мыло — такая же история. Периодически прилетают подобные ошибки.

Тут так и хочется спросить, кто уже догадался что произошло?

Менеджеры жалуются что клиент не может обновить инфу. Проверяю — действительно запрос есть а данные не меняются. Тут же вспоминаю про вчерашние COMMIT-ы принудительные. Ну чем черт не шутит, давай попробуем сделать
show variables like “%autocommit%”;
Получаю ON все правильно, тоже самое их php и… барабанная дробь OFF. (до этого момента признаться вспоминал админов всеми нехорошими словами, а оказывается нет виноват сам)

В итоге — все оказалось банально и просто.

Такс… ну и как такое может быть все ведь работало, смотрим в конфиги и обнаруживаем незначительную детальку.

resources.multidb.dbname.adapter = “pdo_mysql”
resources.multidb.dbname.host = “localhost”
resources.multidb.dbname.username = “user”
resources.multidb.dbname.password = “pass”
resources.multidb.dbname.dbname = “dbname”
resources.multidb.dbname.driver_options.1002 = “SET NAMES utf8;”

переконвертировано

resources: 
  multidb: 
    dbname: 
      adapter: pdo_mysql
      host: localhost
      username: user
      password: pass
      dbname: dbname
      driver_options: 
        - SET NAMES utf8;

как видите при конвертации 1002 превратилось фактически в 0. Дальше если взглянуть чуть глубже увидим
в Zend_Db
// PDO constant values discovered by this script result:
const ATTR_AUTOCOMMIT = 0;

Ну и на последок виновник торжества — Zend_Config_Writer_Yaml

/**
   * Service function for encoding YAML
   *
   * @param int $indent Current indent level
   * @param array $data Data to encode
   * @return string
   */
  protected static function _encodeYaml($indent, $data)
  {
      reset($data);
      $result = "";
      $numeric = is_numeric(key($data));                // look here
 
      foreach($data as $key => $value) {
          if(is_array($value)) {
              $encoded = "n".self::_encodeYaml($indent+1, $value);
          } else {
              $encoded = (string)$value."n";
          }
          $result .= str_repeat("  ", $indent).($numeric?"- ":"$key: ").$encoded;    // and look here
      }
      return $result;
  }

Напоследок хочу добавить что если использовать SymfonyComponents/YAML/sfYaml.php, о котором я упоминал в начале статьи (я написал для него оч простую обертку для удобного использовая в ZF) и добавить в наш пример
$writer->setYamlEncoder(array(‘App_Yaml’, ‘dump’));
то все переконвертируется правильно.

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

Не судите строго — первый пост на хабре.

Автор: wild_honey

* - обязательные к заполнению поля