1

I am working on an iOS application that will use RestKit 0.20 to make REST-based calls to a service that is running on JBoss AS 7.1.1 and using restEASY as its REST-based web service framework.

The REST service that the client app will be calling is used to retrieve objects based on their unique identifier. Since these objects can be small or large (> 1MB in size) and great in number (20? 50? 100 or more at a time) I don't want to make one large call to retrieve them all at once. Rather, I was planning on using RestKit's queued operation support to create a GET request for each object based on the object identifier, and execute the calls asynchronously. Once the GET has completed, each object will be processed through the use of Objective-C blocks so as to avoid any unnecessary blocking.

My RestKit client code looks like this...

    NSArray *identifiers = ...
    RKObjectManager *objectManager = [RKObjectManager sharedManager];

    RKResponseDescriptor *getObjResp = [RKResponseDescriptor responseDescriptorWithMapping:[MyObject mapping] pathPattern:[WebServiceHelper pathForServiceOperation:@"/objects/:uniqueIdentifier"] keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
    for (int i=0; i < identifiers.count; i++) {
        NSString *identifier = [identifiers objectAtIndex:i];
        NSURL *serviceURL = [WebServiceHelper urlForServiceOperation:[NSString stringWithFormat:@"/objects/%@", identifier]];
        NSURLRequest *request = [NSURLRequest requestWithURL:serviceURL];
        RKObjectRequestOperation *requestOp = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[getObjResp]];

        [requestOp setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
            MyObject *obj = [mappingResult firstObject];
            if (self.delegate != nil) {
                [self.delegate didLoadObjectWithIdentifier:identifier myObj:obj];
            }
        } failure:^(RKObjectRequestOperation *operation, NSError *error){
            if (self.delegate != nil) {
                [self.delegate didFinishWithError:error];
            }
        }];

        [objectManager enqueueObjectRequestOperation:requestOp];
    }

From there, the delegate method that gets called when an object has been retrieved looks like this:

-(void)didLoadObjectWithIdentifier:(NSString *)identifier myObj:(MyObject *)myObj {
    if(secureMessage != nil) {
        NSLog(@"Message %@ retrieved successfully : %@:%@", identifier, myObj);
    } else {
        NSLog(@"NO OBJ");
    }
}

The calls appear to be functioning as expected, as I am able to print out information about the retrieve objects. However, I am seeing some weird/unexepcted behavior on the service side.

First, I see a number of Exceptions being thrown by restEASY:

13:22:02,903 WARN  [org.jboss.resteasy.core.SynchronousDispatcher] (http--0.0.0.0-8080-10) Failed executing GET /objects/BBFE39EA126F610C: org.jboss.resteasy.spi.WriterException: ClientAbortException:  java.net.SocketException: Broken pipe
    at org.jboss.resteasy.core.ServerResponse.writeTo(ServerResponse.java:262) [resteasy-jaxrs-2.3.2.Final.jar:]
    at org.jboss.resteasy.core.SynchronousDispatcher.writeJaxrsResponse(SynchronousDispatcher.java:585) [resteasy-jaxrs-2.3.2.Final.jar:]
    at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:506) [resteasy-jaxrs-2.3.2.Final.jar:]
    at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:119) [resteasy-jaxrs-2.3.2.Final.jar:]
    at org.jboss.seam.resteasy.ResteasyResourceAdapter$1.process(ResteasyResourceAdapter.java:145) [jboss-seam-resteasy.jar:2.3.0.Final]
    at org.jboss.seam.servlet.ContextualHttpServletRequest.run(ContextualHttpServletRequest.java:65) [jboss-seam.jar:2.3.0.Final]
    at org.jboss.seam.resteasy.ResteasyResourceAdapter.getResource(ResteasyResourceAdapter.java:120) [jboss-seam-resteasy.jar:2.3.0.Final]
    ...

It would appear as though RestKit is closing the socket somehow (or some other error is preventing the object from being read from the server). I am unable to find anything in the documentation that could explain what is going on here.

Secondly, though, I also see another call for the very same object when a request fails with this error. Why is the GET being called more than once? Is RestKit redoing the failed GET request?

I'm mostly concerned about why the Exception is occurring within restEASY, as it will make it difficult to diagnose calls that really do fail. Has anyone seen this behavior before? Any tips as to how I can correct these issues? Thanks for any help you can give!!

Shadowman
  • 11,150
  • 19
  • 100
  • 198

1 Answers1

1

Those exception are resulted from disconnected Clients i.e. some of the users might quit the app while waiting for the process to complete OR has a network failure (at the client end). Hence, Broken Pipe.

TheWhiteRabbit
  • 15,480
  • 4
  • 33
  • 57
  • as this is result of aborted client, nothing seems wrong at the Service (server) end. OR do you have any timeouts at client / server end (this might also be a case) – TheWhiteRabbit Jan 10 '13 at 11:21
  • Not entirely sure. I only see the errors on the server-side. On the client side, there are no log statements written about errors or connectivity problems. And, as I stated, eventually ALL of the objects are returned. It looks like RestKit is retrying all of the failed attempts and eventually getting everything that was expected. What I have been unable to find, though, is where that retry logic is being called and why there are errors in the first place. – Shadowman Jan 10 '13 at 14:48
  • I should add, I know that there are no clients disconnecting explicitly as I am the only one testing this. I'm seeing this during development, not as part of a production deployment. (I wouldn't be surprised to see things like this in the real-world for the reasons you mentioned above) – Shadowman Jan 10 '13 at 14:48
  • There are no errors at the client side because there are no failed operations that client know of, server is aborting the connection (for some reason). as you are getting response for every request probably client is retrying it on time-out (RestKit have this functionality ?? ) – TheWhiteRabbit Jan 11 '13 at 06:29
  • I'd also suggest to monitor HTTP traffic between client and server this [link](http://stackoverflow.com/questions/11128362/how-to-monitor-network-calls-made-from-ios-simulator) might of help. – TheWhiteRabbit Jan 11 '13 at 06:34