Vous êtes sur la page 1sur 16

PATTERNS FOR ASYNCHRONOUS WEB SERVICE CALLS

John Sadd Engineering Fellow January, 2007 Version 1.0

May, 2013

Page 1 of 16

CONTENTS

INTRODUCTION.....................................................................................................4 New considerations for asynchronous calls................................................................4 MAKING ASYNCHRONOUS CALLS IN OPENEDGE.....................................................6 RUNNING A WEB SERVICE ASYNCHRONOUSLY....................................................11 COORDINATING MULTIPLE CONCURRENT REQUESTS...........................................13 SUMMARY............................................................................................................15

May, 2013

Page 2 of 16

Patterns for Asynchronous Web Service Calls

John Sadd

DISCLAIMER
The information contained in this document represents the current view of Progress Software Corporation on the issues discussed as of the date of publication. Progress reserves the right, in its sole discretion, to modify or abandon without notice any of the plans described herein pertaining to future development and/or business development strategies. Any reference to third party software and/or features is intended for illustration purposes only. Progress Software Corporation does not endorse or sponsor such third parties or software. This White Paper is for informational purposes only. PROGRESS MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS DOCUMENT. No part of this document may be reproduced, stored in or introduced into a retrieval system, or transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or otherwise), or for any purpose, without the express written permission of Progress Software Corporation. Copyright 2007 Progress Software Corporation. All rights reserved.

May, 2013

Page 3 of 16

Patterns for Asynchronous Web Service Calls

John Sadd

INTRODUCTION
This paper is one in a series of documents describing how to use support for Web services in OpenEdge, how to think about the concepts around the term service, and how to take advantage of the larger topic of enterprise integration patterns to design applications and to adapt existing applications to new requirements. You can find all of the papers on PSDN under the topic of SOA for OpenEdge. The paper titled Messaging Patterns for OpenEdge introduces basic message patterns such as Document Message, Command Message, and Event Message, and notes that while in principle each message is a one-way transmission, in OpenEdge messages are most often represented as matched Request-Reply pairs, with input parameters going in one direction and output parameters going in the other. To be sure, it would be entirely possible to construct message sequences in ABL that actually separate request from reply, with one procedure call representing a request message sending data to a requester, and an entirely separate call representing the reply being sent in the other direction. In most cases, this degree of separation is not necessary or appropriate for an OpenEdge application. Even most published Web services expect input parameters representing a request, and return output parameters containing the reply, in a single call. However, there is another aspect of OpenEdge requests, whether in the form of a procedure call to an OpenEdge AppServer, or a Web service request to another environment, which does in effect create a matched pairing of separate request and reply messages. This is in the ABL support for asynchronous calls. When an ABL client session makes an asynchronous call to an AppServer, it sends values for the calls input parameters, and identifies what the output parameters are, but does not expect to receive values for them immediately. Rather, the call returns control as soon as the call with its input parameters is placed on a queue to be handled by an AppServer agent. The caller is notified independently when the request has been processed and output parameters are returned, which allows the client session to continue doing other work in the meantime. OpenEdge ABL has supported asynchronous calls from client to AppServer for a number of product releases. This support can be very useful in any application that separates client from AppServer. A client session, for example, can make a request for a large amount of data to an AppServer and continue client processing until the data is returned. Or a client can request validation of input data from the user interface and allow the user to keep working until the result of the validation comes back from an AppServer call. Some of the features of ProDataSets can also be used effectively with asynchronous requests. For example, if a client-side lookup in a ProDataSet table fails because the requested row has not yet been passed to the client, the handler for the FIND-FAILED event that occurs can make an asynchronous AppServer call to retrieve the needed row without holding up client processing or data entry while it is being retrieved.

New considerations for asynchronous calls


Two important recent developments, one in the product itself, and one in the larger world in which OpenEdge applications now are able to operate, have expanded the potential usefulness of asynchronous requests.

May, 2013

Page 4 of 16

Patterns for Asynchronous Web Service Calls

John Sadd

The change to the product is in OpenEdge release 10.1. In earlier releases, all asynchronous requests to an AppServer are placed into a single queue, so that the AppServer could not start processing a request until the previous one had been completed. This meant that, although the response to each request was received asynchronously by the client, overall throughout could not be increased by allowing multiple requests to be handled concurrently or allowing simpler requests to return before more resource-intensive ones independent of the order in which they were submitted. The only way around this is to send requests to different named AppServers, each with its own pool of agents. Starting in release 10.1, a single AppServer with multiple agents, and configured to run in the Session-Free model, can receive and process multiple requests by sending each request to a different agent, without waiting for each request to finish before the next one is begun. In cases where there is significant database I/O or other work that causes a request to take an appreciable amount of time to complete, this can result in an improvement in overall throughput and more efficient use of AppServer resources. Beyond the examples in this paper, you can learn much more about the OpenEdge support for asynchronous calls from the online Help entries for the various ABL keywords that are used, as well as from the product manual titled Developing AppServer Applications. The change to the larger application world is simply that there are now many other services that an OpenEdge application can take advantage of, using the product support for making requests to other environments as if they were ABL procedure calls. These Web service requests are inherently more unpredictable in their response times and less reliable to return a response at all -- since they go to unknown remote resources across the Internet. When your application makes a request of a Web service that is not under your control, the advantages of making the call asynchronously -- and being prepared for varying response times, or even a timeout that indicates no response at all are clearly multiplied. As with the base support for Web service calls, the good news is that OpenEdge supports asynchronous calls to Web services in the same way as it does for calls to AppServer procedures. In addition, whether youre invoking Web services or running AppServer procedures from an OpenEdge client, theres no additional programming work to do to take advantage of the 10.1 support for handling multiple AppServer requests on multiple agents at the same time. Figure 1 illustrates how the new product support can take advantage of multiple ports that communicate with remote Web services. The same parallelism is supported for multiple agents managed by a Session-Free OpenEdge AppServer as well.

May, 2013

Page 5 of 16

Patterns for Asynchronous Web Service Calls

John Sadd

Figure 1: Sequential versus parallel execution of async requests This paper starts by reviewing the ABL support for making asynchronous requests. It then shows how you can use this same support to make asynchronous Web service requests from OpenEdge. Along the way, the paper notes how some of the aspects of doing this relate to enterprise integration patterns for software development.

MAKING ASYNCHRONOUS CALLS IN OPENEDGE


Making an asynchronous procedure call is a two-step process (by definition), but only slightly more complicated than making a standard synchronous request. Figure 2 shows an extended version of the test procedure RunTestCust_AS.p used in the paper Exposing ABL Procedures as Web Services to run a procedure on an OpenEdge AppServer.

May, 2013

Page 6 of 16

Patterns for Asynchronous Web Service Calls

John Sadd

Figure 2: Sample procedure RunTestCust_AS_async.p The procedure testcust.p is unchanged from the simple procedure used in the earlier paper to return a RETURN-VALUE and an OUTPUT parameter. Running a procedure asynchronously does not require any changes to it at all.

Figure 3: Sample procedure TestCust.p

May, 2013

Page 7 of 16

Patterns for Asynchronous Web Service Calls

John Sadd

Lets look at the lines that extend the procedure beyond what was shown in the earlier paper.

Figure 4: ASYNCHRONOUS code from RunTestCust_AS_async.p 1. First of all, on the RUN statement, you add the keyword ASYNCHRONOUS to tell OpenEdge to make the call asynchronously. Note that there is no change at all to the procedure you are calling. It runs on the AppServer unaware that there is any difference in how it is run. It is in fact the client that becomes asynchronous, continuing on with its work while it awaits the response. 2. Each request generates a dynamic object called an asynchronous request object handle. Optionally you can save off the handle to this object using the SET phrase. Well show how this can be helpful later in the paper when we make multiple calls to a Web service. 3. When you run the procedure you have to tell OpenEdge how to notify you when it completes. You do that by naming an EVENT-PROCEDURE to run when the call completes. This is the name of an internal procedure, which can be in the same procedure file as the call, in which case the qualifier IN THISPROCEDURE is assumed by default. Or you can point to an internal procedure in some other persistent procedure that has already been started, in which case you identify it with the IN <handle> phrase. 4. You specify all the same parameters to the procedure youre running as you would if you were running it synchronously. The INPUT parameters are passed in, but setting the OUTPUT parameters is deferred until the response completes. 5. The MESSAGE statement confirms that when the code runs testcust.p, the RETURN-VALUE is not set, and neither is the OUTPUT parameter cCustName:

May, 2013

Page 8 of 16

Patterns for Asynchronous Web Service Calls

John Sadd

6. So now what do you do? You can continue to run any other client code that lets you keep working while you wait for the request to complete. But the EVENT-PROCEDURE wont be run until one of two things happens: Either you must run the ABL statement PROCESS EVENTS to check for events such as the request completion, or you must get to a WAIT-FOR statement that waits for a signal that youve received every response you were waiting for. You can run PROCESS EVENTS inside a loop or in any other periodic way, and check the ASYNC-REQUEST-COUNT attribute of the server handle to see whether there is still an outstanding request. The next MESSAGE statement shows that right after the RUN statement, the request count is 1:

7. In the test procedure, the code waits for the user event U1, which the event procedure will generate. Alternatively, if you want to wait for a single specific request to complete, as this example does, you could use the statement WAITFOR PROCEDURE-COMPLETE OF hAsyncRequest. The PROCEDURE-COMPLETE event fires automatically for each request when its response comes back. 8. The next MESSAGE shows that when the request has completed and the WAITFOR satisfied, the request count has gone to zero:

Next lets look at the code in the event procedure and how it relates to the code weve already seen.

May, 2013

Page 9 of 16

Patterns for Asynchronous Web Service Calls

John Sadd

Figure 5: EVENT-PROCEDURE code from RunTestCust_AS_async.p 9. As we noted, the EVENT-PROCEDURE phrase names an internal procedure to run when the request completes. 10. The event procedure has to provide an INPUT parameter to match each INPUTOUTPUT or OUTPUT parameter of the original call. Remember that the procedure you are running on the AppServer is blissfully unaware of the fact that the request is being split into two distinct operations. Its calling sequence remains the same, matching the parameters specified in the RUN statement. OpenEdge takes care of mapping the original OUTPUT parameters to the event procedures INPUT parameters for you. 11. The MESSAGE statement confirms that the value in testcust.ps RETURN statement shows up in the event procedure as the RETURN-VALUE, and that the cCustName parameter is set. The GLOBAL SHARED VARIABLE giCallCount confirms that the calling and called procedures are running in different OpenEdge sessions.

12. The event procedure applies the U1 event to satisfy the WAIT-FOR. As noted, this is an alternative to running PROCESS EVENTS to check for completion, or waiting for the requests PROCEDURE-COMPLETE event. There are two additional optional parameters you can pass to the CONNECT request to control asynchronous calls. The first is maxConnections, which controls how many
May, 2013 Page 10 of 16

Patterns for Asynchronous Web Service Calls

John Sadd

concurrent connections can actually be established to handle queued requests. By default the value is zero, which means that there is no limit, but in some circumstances you may want to conserve resources by setting a limit. The other parameter is connectionLifetime, a number of seconds that sets a timeout limit to give control back if a request does not return at all. The default is 300 (so, five minutes). This parameter lets you make sure that a WAIT-FOR will not block the client indefinitely waiting for a response that never comes back. This behavior relates to the enterprise integration pattern named Message Expiration, though some of the potential aspects of that pattern are available only in a full-blown messaging system (such as you can achieve by extending your environment with Sonic). For example, Message Expiration usually provides the capability to route an expired message to a Dead-Letter Channel for later examination. In OpenEdge, however, you cannot determine whether a request has expired because it was never received, or because it took too long to execute, or because the response never got back to you. All you can do is break the WAIT-FOR to get control back and determine what to do. You can then examine the COMPLETE attribute on the request handles to see which requests completed and which did not. For calls to AppServer procedures, there are some additional attributes on the asynchronous object request handle to give you more information on what happened. You can learn more about these from the product documentation and online Help. This completes the review of how to make asynchronous calls to the AppServer.

RUNNING A WEB SERVICE ASYNCHRONOUSLY


You can run a Web service asynchronously just as easily as you can run an AppServer procedure. Heres an extended version of the procedure GoogleEx.p from the paper Accessing Web Services from OpenEdge:

May, 2013

Page 11 of 16

Patterns for Asynchronous Web Service Calls

John Sadd

Figure 6: ASYNCHRONOUS code from GoogleEx_async.p This procedure runs a Web service provided by Google that examines and corrects a possibly misspelled input string. As you can see, you specify the ASYNCHRONOUS keyword, the SET phrase for the request object handle, and the EVENT-PROCEDURE in the same way as running an AppServer procedure. The MESSAGE statement takes a look at some of the attributes of the asynchronous request object handle (you can get details on all of them in the OpenEdge online Help for this topic name).

The values are what you would probably expect: The EVENT-PROCEDURE attribute holds the name of the internal procedure to run on completion. INSTANTIATING-PROCEDURE is the name of the client procedure you are running (its shown as a temp file because its run directly from the editor).

May, 2013

Page 12 of 16

Patterns for Asynchronous Web Service Calls

John Sadd

PERSISTENT-PROCEDURE is set to the pseudo-persistent-procedure that represents the port type in the WSDL document that describes the call. PROCEDURE-NAME is the operation name that you are running in the Web service. The NAME attribute isnt set for this dynamic object, and so has no value. The EVENT-PROCEDURE-CONTEXT is the procedure where the event procedure runs; in this case it is the same as the INSTANTIATING-PROCEDURE.

The event procedure confirms we got the right correction back, and that at this point, the outstanding request count is zero:

You can access the same request object handle in the event procedure using the built-in SELF handle. But the problem with this information is that if you are making multiple calls to the same Web service (with different INPUT parameters) and waiting for all of them to be processed and returned, the attributes dont really tell you anything that you dont already know. What youd like to know are most likely the INPUT parameters that you passed in to each call, so that you know what OUTPUT goes with what INPUT, but these values are not available through the object request handle. The same limitation applies if you are making multiple async calls to an AppServer procedure. There are basically two ways to handle this issue. First, you can make one of the OUTPUT parameters (or possible an INPUT-OUTPUT parameter) the value that you need to use to identify which request is which. This is of course possible only if you control the calling sequence of what you are calling, which for a Web service will not normally be the case. Alternatively you can hang onto the request object handles using the SET phrase in the RUN statement, and match them up with the SELF handle for each response as it comes in. The next section shows an example of how to do this.

COORDINATING MULTIPLE CONCURRENT REQUESTS


One of the main benefits of making asynchronous requests, whether to an AppServer running Session-Free or to one or more Web services, is that the requests can potentially execute concurrently. Even if multiple requests are being executed on a single machine by multiple AppServer agents, I/O requests and other overhead can allow multiple requests to complete more quickly than if they are run in series, and the clients making the requests may be able to make good use of whatever responses come back first, without being held up by a time-consuming request at the head of the sequence. This section expands the Web service example one more time, showing how to make multiple requests concurrently and identify them as the responses are returned. As
May, 2013 Page 13 of 16

Patterns for Asynchronous Web Service Calls

John Sadd

we noted, the attributes of the asynchronous object request handle that can be accessed through SELF are generally not helpful in identifying responses, since the attribute values for a set of requests to the same service will all be the same. The expanded example in Figure 7 shows one way to keep track of requests and match them up with the responses that come in.

Figure 7: GoogleEx_async_multiple.p with 5 concurrent requests In the example, the phrase variable is extended to hold five requests, each of which will be passed in turn to the doSpellingSuggestion service as input. The hAsyncRequest handle is similarly extended to hold five request object handles as the calls are made. In the Spelling_Response event procedure, the request object held in the SELF handle is matched up against the list of request objects held in hAsyncRequest, and then the MESSAGE statement pairs that object up with the corresponding entry in the phrase variable. The event procedure also keeps track of the number of outstanding requests and uses the U1 event to cancel the WAIT-FOR when that count goes to zero, as this sequence of messages shows:

May, 2013

Page 14 of 16

Patterns for Asynchronous Web Service Calls

John Sadd

Figure 8: Responses from five concurrent asynchronous requests Remember that in principle, the responses could come back in any order. For a larger number of requests, or a more complex combination of requests that could be outstanding at the same time, you can also use a temp-table to hold an unlimited number of request object handles and whatever information is required to associate them with their responses. Its also possible to walk the chain of all outstanding asynchronous requests using the FIRST-ASYNC-REQUEST and NEXTSIBLING attributes on the server handle, though of course that list by itself will not provide you with the parameter information you may need to identify which request goes with which response. The request handles and parameter values that the procedure keeps track of are examples of the enterprise integration pattern called Correlation Identifier. A request in a Request-Reply pair typically includes a Message ID, and the reply sends that same value back as the Correlation ID. The Correlation Identifier that you get using ABL is the object request handle. As we discussed, if you have control over the parameter list of the call, you can actually make the Correlation Identifier a parameter that is part of the request and part of the reply. Otherwise you have to keep track of the key values that identify the request in a meaningful way yourself.

SUMMARY
OpenEdge ABL has supported asynchronous AppServer calls for quite some time, and improvements to that support in release 10.1 make it more useful than ever. In addition, the prospect of extending your OpenEdge application using Web services increases the likelihood that asynchronous requests will be a useful and even necessary part of a successful design. Once you understand the basic of how to implement async requests, they do not need to add undo complication to your application design, especially if you standardize how they are used in your client-side Service Interfaces, which isolate the rest of the client code from the particulars of a request to a service provider. Integrating asynchronous support into your design can make your application more effective, more flexible, and more adaptable as you move forward.

May, 2013

Page 15 of 16

Patterns for Asynchronous Web Service Calls

John Sadd

Corporate Headquarters Progress Software Corporation, 14 Oak Park Drive, Bedford, MA 01730 USA Tel: 781 280 4000 Fax: 781 280 4095 Europe/Middle East/Africa Headquarters Progress Software Europe B.V. Schorpioenstraat 67 3067 GG Rotterdam, The Netherlands Tel: 31 10 286 5700 Fax: 31 10 286 5777 Latin American Headquarters Progress Software Corporation, 2255 Glades Road, One Boca Place, Suite 300 E, Boca Raton, FL 33431 USA Tel: 561 998 2244 Fax: 561 998 1573 Asia/Pacific Headquarters Progress Software Pty. Ltd., 1911 Malvern Road, Malvern East, 3145, Australia Tel: 61 39 885 0544 Fax: 61 39 885 9473 Progress is a registered trademark of Progress Software Corporation. All other trademarks, marked and not marked, are the property of their respective owners.

www.progress.com
Specifications subject to change without notice. 2013 Progress Software Corporation. All rights reserved.

May, 2013

Page 16 of 16

Vous aimerez peut-être aussi