Tuesday, June 30, 2009

Measuring LiveCycle Performance: Errors

There are several ways to measure LiveCycle performance. One of them is to call appropriate method on MessagePerformanceUtils class. This approach is pretty straightforward but sometimes you might get an error:

Destination '...' either does not exist or the destination has no channels defined (and the application does not define any default channels.)

That means your are using statically configured channels and you don't package services configuration into the SWF file. To fix it, in the Flex Builder add config files folder to Flex source path and specify 'services' compiler argument:

 

Although it solves the problem, this approach is not suitable for real project as you don't want to compile SWF file with hard coded services configuration. Instead of that you would create dynamic channels on the client side, and configure them using IoC framework (i.e. Parsley, Prana or your own). And if you do that you will most likely get the following error:

Error: Message is missing MPI headers. Verify that all participants have it enabled

The reason of that is: you configured MPI headers only on the server side, but not on the Flex side. To fix it, you need to set recordMessageTimes and recordMessageSizes properties of Channel class to true. The problem is that those properties are read-only, so you cannot assign them to any value directly. But here is a trick: you can use applySettings() method:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="init()">
<mx:Script>
<![CDATA[
import mx.messaging.Channel;
import mx.messaging.ChannelSet;
import mx.messaging.channels.RTMPChannel;
import mx.messaging.events.MessageEvent;
import mx.messaging.messages.MessagePerformanceUtils;

private function init():void {
ds.channelSet = createChannelSet();
}

private function createChannelSet():ChannelSet {
var channels:Array = new Array();
channels.push(createRtmpChannel());

var result:ChannelSet = new ChannelSet();
result.channels = channels;
return result;
}

private function createRtmpChannel():Channel {
var result:Channel = ... // get it from IoC
result.applySettings(customSettings());
return result;
}

private function customSettings():XML {
return <channel-definition>
<properties>
<record-message-times>true</record-message-times>
<record-message-sizes>true</record-message-sizes>
</properties>
</channel-definition>;
}


private function messageHandler(event:MessageEvent):void {
var performanceUtils:MessagePerformanceUtils = new MessagePerformanceUtils(event.message);
statistics.text = performanceUtils.prettyPrint();
}
]]>
</mx:Script>

<mx:DataService id="ds" destination="MyDestination" result="messageHandler(event)" />
<mx:ArrayCollection id="domainObjects" />
<mx:TextArea id="statistics" />
</mx:Application>

Resources

• Check out example sources from GitHub.