I am using Google AppEngine, in conjunction with PyAMF to provi开发者_开发技巧de RemoteObject support. In my Flex code I make several RemoteObject method calls at once which tends to batch the AMF Messages into a single HTTP request.
Most of the time this is fine but AppEngine applies some strict per request limits (in this case I am hitting a DeadlineExceededError - max 30 seconds). A number of service methods are expected to take upwards of 10 seconds and if these are batched by the RemoteObject into 1 HTTP .. you see where this is going.
Now you could say refactor your service calls and that is also going on but not really the question being asked here. Is there a way to prevent Flex RemoteObject from batching AMF requests for situations like this?
I have done a fair amount of Googling on the subject and come up with bupkis. It seems to me that I would need to implement a custom version of mx.messaging.channels.AMFChannel
or something of that nature, which seems waay too hardcore for a feature like this ..
Anyone have any pointers/insight?
Check out the concurrency property on RemoteObject.
The batching of AMF requests into HTTP happens at the NetConnection level. So unfortunately the best way to stop AMF requests from batching is to implement a custom version of the mx.messaging.channels.AMFChannel. However this is quite easy to do, and probably easier that queuing requests and calling them later.
Instead of using the default AMFChannel use the following instead:
package services
{
import flash.events.AsyncErrorEvent;
import flash.events.IOErrorEvent;
import flash.events.NetStatusEvent;
import flash.events.SecurityErrorEvent;
import flash.net.NetConnection;
import mx.messaging.MessageResponder;
import mx.messaging.channels.AMFChannel;
public class NonBatchingAMFChannel extends mx.messaging.channels.AMFChannel
{
public function NonBatchingAMFChannel(id:String = null, uri:String = null)
{
super(id, uri);
}
override protected function internalSend(msgResp:MessageResponder):void
{
// AMFChannel internalSend
super.internalSend(msgResp);
// Reset the net connection.
_nc = new NetConnection();
_nc.addEventListener(NetStatusEvent.NET_STATUS, statusHandler);
_nc.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
_nc.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
_nc.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler);
_nc.connect(this.url);
}
}
}
The magic happens by overriding the internalSend method. After running the super internalSend method (which queues the message responder), we will reset the NetConnection and all of its event handlers. This gets a new NetConnection ready for the next remoting message.
Note: It's important to note that this is a custom non batching AMFChannel, if you want send AMF messages securely you'll need to copy this class and extend the mx.messaging.channels.SecureAMFChannel class.
Credit: Credit to Nick Joyce who answered his question here on a different forum.
you can create a pool of connections, and create another another class that triggers the connections. Your application does not make the connections, only feeds the pool.
Well, one way is apparently to roll your own AMFChannel that doesn't use NetConnection... I haven't tried it so I don't know how well it works. http://blogs.adobe.com/pfarland/2008/06/using_amf_with_flashneturlload.html
I think what njoyce like to do is to prevent AMF batching. This ie. is good for multiple small calls but if you have very server-intensive calls you AMF batching should be prevented. Why?
- one AMF call => one thread on server side
- multiple AMF calls => all requests get handled through multiple threads
Pseudo Code:
private static var _collectionFillIndex:int;
private static var _collectionsToFill:Array = [];
public function doFillCollections():void {
_collectionFillIndex = _collectionsToFill.length;
Application.application.addEventListener( Event.ENTER_FRAME, onFrameEventHandler );
}
private function onFrameEventHandler( event:Event ):void {
--_collectionFillIndex;
if( _collectionFillIndex < 0 ) {
Application.application.removeEventListener( Event.ENTER_FRAME, onFrameEventHandler );
return;
}
_collectionsToFill[ _managerFillIndex ].fill();
}
精彩评论