3

I am using Google AppEngine, in conjunction with PyAMF to provide 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?

njoyce
  • 628
  • 4
  • 8

5 Answers5

1

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.

splash
  • 12,499
  • 1
  • 40
  • 64
brettlaforge
  • 2,841
  • 2
  • 14
  • 13
1

Check out the concurrency property on RemoteObject.

James Ward
  • 28,966
  • 9
  • 47
  • 79
  • Looking at these docs (and correct me if I'm wrong) my problem seems to be subtly different - I would like ensure that each AMF Message sent via the RemoteObject is sent by one HTTP Request (and be able to make multiple calls without error). I dug through the Flex SDK and it doesn't appear that the Messaging RPC is batching the requests which leads me to assume that it is occurring in the underlying NetConnection? – njoyce Jan 12 '10 at 00:41
  • 2
    Yes. You are right. The Flash Player waits until the frame ends to send all queued network requests. If you move each request onto a different frame (like with callLater) then it will insure that each request actually uses a different HTTP network request. – James Ward Jan 12 '10 at 01:22
  • Thanks! That info was enough for me to be able to put my calls into a queue and stagger them accordingly. – njoyce Jan 12 '10 at 05:30
  • 1
    Even doing one RemoteObject call per callLater() cycle, I can't reliably avoid messages with more than one call. Is there some trick to it? – rakslice Nov 24 '11 at 07:20
0

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();
    } 
Frank Szilinski
  • 540
  • 1
  • 5
  • 18
0

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.

0

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

rakslice
  • 7,846
  • 3
  • 47
  • 51