Чтобы добавлять сообщения и комментарии, .

@yzh44yzh:
yzh44yzh

запустился, работает, бодро пишет в логи. Но коннекты от клиентов не принимает. Это весьма досадно (

@yzh44yzh:
yzh44yzh

FMS4 Ставится и работает на RedHat производных дистрибутивах. Скрипт-инсталятор можно и вовсе не запускать, достаточно вручную подредактировать conf/fms.ini

В скриптах для запуска нужно удалить код, проверяющий версию ОС. Ну или можно не удалять, он безобидный, только варнинги выдает.

@yzh44yzh:
yzh44yzh

Ну пришло таки время ставить FMS4

WARNING: Your Linux distribution, RedHat i686 is not supported by this
installer.

Ага, напугал. Все равно будешь у меня работать )

@yzh44yzh:
yzh44yzh

ох, N месяцев с ним не работал, все забыл, и теперь приходится лазить в документацию )

@yzh44yzh:
yzh44yzh

Цитата:
Дальше начинается просто вакханалия крючкотворства. Дело в том, что Adobe выблевнула в 2009 году «спецификацию» RTMP. Этот документ описывает некоторый протокол, который очень похож на RTMP и Adobe упорно называет то, что описывает этот документ, как RTMP. И более того: в документе сказано, что после прочтения этого документа, вы не имеете права реализовывать RTMP серверы иначе, кроме как по этому документу. Отступление на один байт от этого документа лишает вас права использовать этот документ.

levgem.livejournal.com

@yzh44yzh:
yzh44yzh

Эх, могучая сила flash.utils.Proxy только что съела час моего времени :)

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

Сейчас в быстром прототипе этот же класс и принимал вызовы с сервера. И вот сервер пытается вызывать метод, который я забыл определить в FmsSevice. И чего происходит? FmsService вызывает такой метод с таким же именем на сервере! Который, к несчастью, там оказался в наличии.

Выводы:
1) Прокси — опасная штука, способная ловко прятать причину бага
2) Не стоит идентично называть методы на клиенте и на сервере

@yzh44yzh:
yzh44yzh

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

Вот очередная статья на сайте (глава в книге) yzh44yzh.com

Предлагаю высказаться по наброску оглавнения книги github.com (хотя может еще рано).

И анонсирую новый проект github.com Ну как новый, для меня-то старый. Просто раньше не выкладывал.

@yzh44yzh:
yzh44yzh

На FMS в ServerSide ActionScript обработка исключений практически бесполезна. Исключение можно бросить throw, можно поймать в try..catch. А вот если оно не поймано, то оно тупо останавливает выполнение программы, но не выводит никаких сообщений ни в лог ни в консоль. Пусто вообще. Так что от этого больше вреда, чем пользы.

@yzh44yzh:
yzh44yzh

If there are several simultaneous connection requests for an application, the server serializes the requests so that only
one application.onConnect() handler is executed at a time. It’s a good idea to write code for the
application.onConnect() function that is executed quickly to prevent a long connection time for clients.

Бля, я идиот, и почему я раньше этого не замечал в документации? У меня onConnect — весьма тяжелый метод. Надо переделать.

@yzh44yzh:
yzh44yzh

Сколько лет я работаю с этим сервером, столько лет меня преследует проблема, что он не всегда детектит дисконнект клиентов. Юзер закроет браузер, выключит комп, а FMS все равно будет думать, что соединение с клиентом есть. Это происходит редко, но стабильно.

Это известная проблема FMS.

И из-за этого во всех наших FMS приложениях существуюет костыль, входящий с состав нашей core-fms-библиотеки — клиент каждые N секудн посылает запрос keepAlive, а сервер запоминает timestump, когда был получен последний такой запрос от данного клиента. Затем сервер каждые M секунд (M примерно равно N * 2) перебирает массив application.clients и проверяет timestump каждого клиента. Те, кто давно не посылал keepAlive — зомби, и их нужно убирать.

Увы, с этим костылем переодически возникает другая проблема — FMS ошибочно дисконнектит живых клиентов. По каким-то неизвестным причинам изредко бывает так, что timestump клиента устарел, хотя клиент жив и спокойно работает.

Сча придумал еще один костыль поверх — клиентов с устаревшим timestump не удалять сразу, а посылать им запрос areYouAlive(someUniqueKey), на который клиент должен ответить someUniqueKey. Живой клиент ответит, зомби нет.

Запрос, ясное дело, асинхронный. Так что еще нужно будет и здесь реализовать timeout на ожидание ответа клиента.

В общем, хак на хаке. Так и живем :)

@yzh44yzh:
yzh44yzh

А кому-нибудь нужны всякие либы для разработки под FMS? Например, поддержка юнит-тестов, или вот yzh44yzh.com тул для профилирования по производительности.

Хотя я и так знаю, что никому не нужно. Но все равно буду выкладывать, не отвертитесь :)

@Constantiner:
Constantiner

Ну вот уже несколько дней подряд натыкаемся на говно в нашем FMS-сервере. Понаписан JS-код, который ни отладить, ни понять, для которого нет нормальной IDE. В итоге исправляются одни проблемы и неизбежно возникают другие. А также идет хождение по кругу проблем, когда исправленная пару недель назад проблема реинкарнирует. Кто додумался выбрать JS в качестве серверного языка? Очевидно, это был очень умный человек :)

@yzh44yzh:
yzh44yzh

Надо профилировать. Надо пораскинуть мозгами, как это сделать :)
Для начала нужно напустить на него кучу клиентов-ботов :)

@yzh44yzh:
yzh44yzh

по мере тестирования одного и того же приложения на трех медиасерверах заметил:
— запуск сервера самый быстрый у wowza, медленне у red5, самый медленный у fms (правда это включая запуск админ-сервера)
— коннект приложения к wowza и red5 примерно одинаково быстрый, к fms чутка медленне, заметно на глаз

@yzh44yzh:
yzh44yzh

и если уж речь зашла о несовместимостях, которые добавляет red5, то вот это:
rtmp://domain/app/room1/room2/room3/ тоже не будет работать на fms.

@kutu:
kutu

вышел FMS4 теперь с p2p
adobe.com

@Constantiner:
Constantiner

А есть тут спец по Flash Media Server, который может дать линк на best practices по отладке взаимодействия с FMS? А то Charles его не берет, а говно откуда-то прет :(

@yzh44yzh:
yzh44yzh

Итак, нам нужно в течение N часов мониторить расход памяти. К сожалению сервак под виндой. а не под линуксом, так что top не катит. Заходим на сервак через RemoteDesktop, запускаем TaskManager, видим дюжину процессов FMSCore.exe. Какой из них нужен мне, не ясно. Но это и не важно, будем мониторить все сразу :)

Так, а как мне сравнить цифры через 2 часа с теми, что есть сейчас? Снимаю скриншот, вырезаю из него Task Messenger. Кладу слева скриншот, справа реальный TaskManager. Вот пусть так и лежать, буду поглядывать на них каждые N минут в течение N часов :)

@yzh44yzh:
yzh44yzh

Я идиот, нафиг debug console, память можно было простым top мониторить...

@yzh44yzh:
yzh44yzh

И да, вам еще нужно как-то догадаться, что там течет память. Ибо приложение тупо падает после двух часов работы, и никакой инфы в логах.

Вы, конечно, скажете, что есть debug console, и что можно мониторить нагрузку на проц и память в реальном времени. Да, можно. Если дебаг-консоль любезно согласится это показать. А то ведь она, зараза, может и не показывать ничего.

@yzh44yzh:
yzh44yzh

Короче, если вы делаете приложение под FMS, и там течет память, то вам понадобится интуиция и удача, чтобы это пофиксить. Других средств борьбы с утечкой нет.

@yzh44yzh:
yzh44yzh

N лет мы используем FMS как сервер приложений, а не просто медиа-сервер. И вот спустя эти N лет я скажу, что в этой роли FMS — говно. У него есть существенный недостаток.

Если сервер долго работает под нагрузкой, то рано или поздно случаются сбои. FMS не исключение. Но вот у него нет никаких средств диагностики. Что сломалось? Как исправить? Что сделать, чтобы такое не случалось в будущем? Узнать невозможно. Да, ты можешь напихать кучу трейсов в своем коде, но это не всегда помогает.

Обычно в таких случаях начинается шаманство: перегрузить сервер, удалить shared objects и т.д. На какое-то время это может помочь. До следущего сбоя.

Фигня в общем. Переход на Java (Scala, Groovy) для нас неизбежен...

@yzh44yzh:
yzh44yzh

Возвращаясь к вопросу о передаче данных с FMS в классы-модели на стороне клиента. Сейчас сделано так, что существует специальный объект FmsClient, который принимает все данные с FMS. Для этого в нем определены методы, кои FMS и дергает со своей стороны. Ну а дальше этот FmsClient кидает кастомные события. Их ловит карта и вызвает методы в моделях. Ну и так модели получают данные.

Схема довольно типичная. Как выяснилось, так оно не только в Mate, но и в PureMVC тоже сделано похоже. Но схема довольно утомительная. Моделей много, методов, которые дергает FMS, тоже много. Кастомные события, карты — overhead.

И тогда пришла в голову мысль как-нибудь сделать так, чтобы сами классы-модели принимали инфу с FMS. На первый взгляд мысль интересная. На второй взгляд — сложно реализуемая. Проблема в том, что для одного NetConnection может быть только один объект, принимающий данные с FMS (FmsClient). Иметь несколько NetConnection нежелательно по ряду причин. В основном потому, что это существенно усложнит логику на стороне сервера (один клиент будет представлен сразу несколькими соединениями).

На третий взгляд мысль все равно интересная и таки реализуемая не очень геморным способом. Надо создавать FmsClient как пустой динамический объект:
netConnection.client = new Object();

Передавать ссылку на этот объект во все модели, а каждая модель примешает к нему те методы, через которые она заинтересована получать данные с FMS.

class MyModel
{
public function init(fmsClient : Object) : void
{
fmsClient.onSomeData = this.onSomeData;
fmsClient.onOtherData = this.onOtherData;
}
}

Выглядит интересно, неприменно попробую на досуге.
Мир жава — статика и строгая типизация. Мир FMS — динамика и замыкания :)

@yzh44yzh:
yzh44yzh

работающий вариант:
flash_proxy override function callProperty(methodName : , ... args) :
{
this[methodName].apply(this, args);
return null;
}

flash_proxy override function hasProperty(name : *) : Boolean
{ return true; }

flash_proxy override function getProperty(name : ) :
{
return function(... args) : *
{
// NOTE this is same as
//nc.call(methodName, null, args[0], args[1], ..., args[N]);

args.unshift(null);
args.unshift(name);
nc.call.apply(nc, args);

return null;
}
}

@yzh44yzh:
yzh44yzh

Попробовал применить flash.utils.Proxy в классе FmsService, который отвечает за общение с FMS сервером.
Было так:
public function SendMessage(roomID : String, message : MessageVO) : void
{ nc.call('SendMessage', null, roomID, message); }

public function ChangeColor(color : int) : void
{ nc.call('ChangeColor', null, color); }

public function ChangeStatus(status : int) : void
{ nc.call('ChangeStatus', null, status); }
Стало так:
flash_proxy override function callProperty(methodName : , ... args) :
{
// NOTE this is same as
//nc.call(methodName, null, args[0], args[1], ..., args[N]);

args.unshift(null);
args.unshift(methodName);
nc.call.apply(args);

return null;
}
Это работает, пока к FmsService не идут обращения от Mate из EventMap. Оттуда не вызывается callProperty, а вызывается hasProperty и getProperty. Попробовал как-то так:
flash_proxy override function getProperty(name : ) :
{
return function(... args) : *
{
args.unshift(null);
args.unshift(name);
nc.call.apply(args);

return null;
}
}
не работает :(
К сожалению нет времени с этим копаться, попробую в другой раз.

@yzh44yzh:
yzh44yzh

BAFPUG прошел успешно, было интересно. Сам я выступил, говорят, неудачно: рассказывал плохо, на слушателей не смотрел, мямлил. Ну бывает, не выспался. Надеюсь, в письменном виде оно лучше выглядит yzh44yzh.com

@yzh44yzh:
yzh44yzh

Оказывается FMS стартует раньше апача, подло захватывает 80й порт и не дает апачу запустится. Вот не ожидал от него такой подлости. И ведь это недавно появилось :(

@yzh44yzh:
yzh44yzh

В очередной раз ставлю FMS на линукс. И есть изменения в этом процессе. Раньше он ставился только на Red Hat Enterprise, и нужно было в инсталяторе (bash-скрипт) удалять сроки проверяющие версию ОС. Теперь инсталятор довольствуется любым линуксом (uname -s должен вернуть Linux).
Еще инсталлятор зачем-то предлагает установить apache (видимо для http туннелинга).
А еще в скачано с сайта адоба zip зачем-то лежит экзешник, а все нужное запаковано еще раз в tar.gz

@yzh44yzh:
yzh44yzh

Юнит-тесты приживаются, хоть и не без трудностей. В серверной части они применяются относительно просто. Но я пока весьма смутно себе представляю, как их применять в клиенской части. Отложим это на неопределенное будущее :)

@yzh44yzh:
yzh44yzh

Встретив коварную и трудноотлавливаемую ошибку, после того, как она найдена и исправлена, надо придумать и внедрить принципы написания кода, исключающие появление таких ошибок в будущем. Это актуально для любого языка, а для FMS в особенности.

@yzh44yzh:
yzh44yzh

Все-таки сделал так:

if(G.ClientManager) Core.Error('ClientManager is already exists');
G.ClientManager = {};
G.ClientManager._clients = new Hash();

Две лишние буквы в имени объекта — не смертельно, а мудрить особо нет времени, надо двигаться вперед.

@yzh44yzh:
yzh44yzh

Эх, жаль, что нет try-catch. Оказывается я даже не могу проверить существование объекта в глобальной области видимости. Такой код
if(ClientManager) Core.Error('ClientManager is already exists');
вылетает с ошибкой.

С ходу придумывается, завести специальный объект для создания области видимости и создавать все остальные объекты в нем (или использовать с той же целью объект Application)
global = {};
if(global.ClientManager) Core.Error('ClientManager is already exists');
global.ClientManager = {};
Но так делать нифига не хочется. Надо что-то получше придумать :(

@yzh44yzh:
yzh44yzh

до сих пор синглтон-объекты создавал так:

ClientManager = {};
ClientManager._clients = new Hash();

ClientManager.GetTotal = function()
{
return this._clients.total;
}

Теперь буду создавать так:

if(!ClientManager) Core.Error('ClientManager is already exists');
ClientManager = {};
ClientManager._clients = new Hash();

@yzh44yzh:
yzh44yzh

Все-таки Server Side ActionScript — коварный язык, ногу прострелить легко. Все свойства и методы любых объектов всегда public.

Вот вызываешь себе ClientManager.GetTotal() а тут бац — нет такого метода в этом объекте. Мистика, отладка, рестратры FMS сервера и другие пляски с бубном.

А оказывается где-то в другом месте кода написано ClientManager = {}
И все, объект обнулен, все его свойства и методы потеряны :)