In Apigee, how do I catch faults connecting to the target server? - apigee

Suppose I have this target defined:
<TargetEndpoint name="default">
<PreFlow name="PreFlow">
<Request/>
<Response/>
</PreFlow>
<HTTPTargetConnection>
<URL>http://host1.example.com:39282</URL>
</HTTPTargetConnection>
<PostFlow name="PostFlow">
<Request/>
<Response/>
</PostFlow>
<FaultRules>
....
</FaultRules>
</TargetEndpoint>
How do I catch target errors like "Connection refused", which would occur when the target is not listening on the given port, or "Host not reachable", which would occur if there is no route to the given host or if the DNS name is not resolvable?
Basically I want the recipe for how to specify the FaultRule that would be placed inside the FaultRules element above.
<FaultRules>
<FaultRule name="catch1">
<Condition>WHAT GOES HERE???</Condition> <!--- ??? --->
<Step>
<Name>AssignMessage-1</Name>
</Step>
</FaultRule>
<FaultRule name="catch2">
<Step>
<Name>AssignMessage-2</Name>
</Step>
</FaultRule>
</FaultRules>

You can use the fault.name variable to check the error (http://apigee.com/docs/api-services/content/policy-attachment-and-enforcement#policy-based-fault-handling)
For example:
<TargetEndpoint name="default">
<FaultRules>
<FaultRule name="bad_network">
<Condition>(fault.name = "ServiceUnavailable")</Condition>
...
The way I got to 'ServiceUnavailable' as the fault name, was by first having the FaultRule policy with no conditions, and then trying a few 'bad target' scenarios - right address/wrong port and wrong address/name both generate the same fault name and can be caught using the above snippet.
To see the error name, you just need to add in an AssignMessage policy a block to read the fault.name variable and in the trace it'll be displayed in the 'Variables Got' session, or assign it to the payload of your response.
Once you have captured all the faults you want to handle, you can go back and modify the proxy faultrules session.
One last note, the FaultRule session above must be in the target endpoint for it to catch the network error on the target side.
Cheers,
Ricardo

yeah!, working, its important where you put the FaultRule: "TargetEndpoint", i was wrong setting in "ProxyEndpoint"
my example:
`<TargetEndpoint name="TargetEndpoint">
<Description/>
<FaultRules>
<FaultRule name="HTTPError">
<Step>
<Name>Raise-Fault-5xx</Name>
<Condition>message.status.code = 503</Condition>
</Step>
</FaultRule>
</FaultRules>
...
`

Related

Whats the relation between load and for?

I am trying tsung for the first time, however, I need some clarification.
I am using load tag as:
<load>
<arrivalphase phase="1" duration="1" unit="minute">
<users maxnumber="100000" interarrival="0.01" unit="second"/>
</arrivalphase>
</load>
But, how would the for loop below works ?:
<sessions>
<session name="root" probability="100" type="ts_http">
<for from="1" to="2" var="i">
<request>
<http url="/test/counter" method="POST" contents="bla=blu&name=glop">
</http>
</request>
</for>
</session>
What I thought is that the loop will count from 1 to 2, thus, sending only two requests, however, when I run the xml file, I got hundred of requests! Does this mean that each user in arrivalphase will send two requests as in the for loop above?
Can someone explain, what's the relation between the for tag and load tag as in the above example?
Your analysis is right , during the first 1 minute of the test , you created 100 users per second,each user will send two requests as in the for loop above。
The load define tsung generate rules of the user, the session define every user needs to perform logic.

Holding data processing for incomplete data sets with Mule and a collection-aggregator

I need to collect and process sets of files generated by another organization. For simplicity, say that the set consists of two files, a summary file and a detail file named like: SUM20150701.dat and DTL20150701.dat, which would constitute a set for date 20150701. The issue is, sets need to be processed in order, and the transmission of files from an outside organization can be error prone such that a file may be missing. If this occurs, this set of files should hold, as should any following sets that are found. As example, at the start of the mule process, the source folder may have in it: SUM20150701.dat, SUM20150703.dat, DTL20150703.dat. That is, the data set for 20150701 is incomplete while 20150703 is complete. I need to have both data sets hold until DTL20150701.dat arrives, then process them in order.
In this simplified form of my mule process a source folder is watched for files. When found, they are moved to an archive folder and passed to the collection-aggregator using the date as the sequence and correlation values. When a set is complete, it is moved to a destination folder. A lengthy timeout is used on the collector to make sure incomplete sets are not processed:
<file:connector name="File" autoDelete="false" streaming="false" validateConnections="true" doc:name="File">
<file:expression-filename-parser />
</file:connector>
<file:connector name="File1" autoDelete="false" outputAppend="true" streaming="false" validateConnections="true" doc:name="File" />
<vm:connector name="VM" validateConnections="true" doc:name="VM">
<receiver-threading-profile maxThreadsActive="1"></receiver-threading-profile>
</vm:connector>
<flow name="fileaggreFlow2" doc:name="fileaggreFlow2">
<file:inbound-endpoint path="G:\SourceDir" moveToDirectory="g:\SourceDir\Archive" connector-ref="File1" doc:name="get-working-files"
responseTimeout="10000" pollingFrequency="5000" fileAge="600000" >
<file:filename-regex-filter pattern="DTL(.*).dat|SUM(.*).dat" caseSensitive="false"/>
</file:inbound-endpoint>
<message-properties-transformer overwrite="true" doc:name="Message Properties">
<add-message-property key="MULE_CORRELATION_ID" value="#[message.inboundProperties.originalFilename.substring(5, message.inboundProperties.originalFilename.lastIndexOf('.'))]"/>
<add-message-property key="MULE_CORRELATION_GROUP_SIZE" value="2"/>
<add-message-property key="MULE_CORRELATION_SEQUENCE" value="#[message.inboundProperties.originalFilename.substring(5, message.inboundProperties.originalFilename.lastIndexOf('.'))]"/>
</message-properties-transformer>
<vm:outbound-endpoint exchange-pattern="one-way" path="Merge" doc:name="VM" connector-ref="VM"/>
</flow>
<flow name="fileaggreFlow1" doc:name="fileaggreFlow1" processingStrategy="synchronous">
<vm:inbound-endpoint exchange-pattern="one-way" path="Merge" doc:name="VM" connector-ref="VM"/>
<processor-chain doc:name="Processor Chain">
<collection-aggregator timeout="1000000" failOnTimeout="true" doc:name="Collection Aggregator"/>
<foreach doc:name="For Each">
<file:outbound-endpoint path="G:\DestDir1" outputPattern="#[function:datestamp:yyyyMMdd.HHmmss].#[message.inboundProperties.originalFilename]" responseTimeout="10000" connector-ref="File1" doc:name="Destination"/>
</foreach>
</processor-chain>
This correctly processes sets found in order if all sets are complete. It correctly waits for incomplete sets to fill, but does not hold following sets, that is in the above example set 20150703 will process while 20150701 is still waiting for the DTL file.
Is there a setting or another construct which will force the collection-aggregator element to wait if there is an earlier collection which is not complete?
I am using the date part of the file name for both the correlation and sequence ID’s which does control that sets process in the order I want if all sets are complete. It is not important if dates do not exist (as with 20150702 in this case), only that existing files are processed in order and that sets must be complete.
In the end, I could not get the Collection-Aggregator to do this. To overcome this, I built a Java class which contain Maps for the SUM and DTL files, with the Correlation ID as the key, and a sorted list of open keys.
The Java class then monitored for a completed set on the smallest key and signals back to the Mule flow when that set is available for processing.
The Mule flow must be put into synchronous mode while processing the files to prevent a data race situation. When complete, it signals the Java class that the processing is complete and the set of data can be dropped from the list/Maps, and receives an indication back if the next set is ready to process.
It is not the prettiest, and I would have preferred to not have used custom features for this, but it gets the job done.

Defining Multiple Proxy Endpoints

This is probably an unusual case as I'm trying to define a new Proxy Endpoint in an API Proxy.
Let's say I have a default Proxy Endpoint with a Conditional Flow to match /myflow and action == GET and that works fine.
then I defined a new Proxy Endpoint (new_endpoint) with its own Conditional Flow to match /mynewflow and action == GET.
/mynewflow works fine and goes to the new_endpoint as expected.
however
/myflow is also now going to new_endpoint! (i used the Trace tool and confirmed it).
Here is the HTTP Proxy Connection Settings for both:
<HTTPProxyConnection>
<BasePath>/v2</BasePath>
<Properties/>
<VirtualHost>default</VirtualHost>
<VirtualHost>secure</VirtualHost>
</HTTPProxyConnection>
<RouteRule name="default">
<TargetEndpoint>default</TargetEndpoint>
</RouteRule>
Is this expected? If it is, how do I make sure that /myflow routes to default Proxy Endpoint?
Looks like you're missing your <RouteRule> in your proxy. Just like the ConditionalFlow, you need a second RouteRule to point to your new target, which would look something like this:
<HTTPProxyConnection>
<BasePath>/v2</BasePath>
<Properties/>
<VirtualHost>default</VirtualHost>
<VirtualHost>secure</VirtualHost>
</HTTPProxyConnection>
<RouteRule name="new_endpoint">
<TargetEndpoint>new_endpoint</TargetEndpoint>
<Condition>(proxy.pathsuffix MatchesPath "/mynewflow")</Condition>
</RouteRule>
<RouteRule name="default">
<TargetEndpoint>default</TargetEndpoint>
</RouteRule>
You don't need to include individual verbs, because we can assume everything to /mynewflow is going to go to the new_endpoint target.
Also, make sure you put the conditional RouteRule above the default RouteRule -- Apigee will match the first one so if default (no condition) is first, you will never match the condition on the remaining rules.
I learned something today: apparently it's HttpProxyConnection/BasePath dictates which Proxy Endpoint is selected
as soon as made sure that the BasePath is different for both endpoints, routing started the way I expected it to.

One API proxy calling two different target endpoints

i have just started working with Apigee.
I want to create one API proxy which will call two target endpoints based on 'if' condition.
i have created an API and added resources to it but the problem is in this case i am getting two API's .
If thetype='abc' target point should be target1
if thetype='xyz' target point should be target2
Can anyone please tell me how to proceed with it ?
Check out the answer to this question. The details of finding the RouteRules is listed there. The ProxyEndpoint documentation will also be helpful.
You can accomplish what you are attempting using this code:
<RouteRule name="routeToTarget1">
<Condition>thetype == "abc"</Condition>
<TargetEndpoint>target1</TargetEndpoint>
</RouteRule>
<RouteRule name="routeToTarget2">
<Condition>thetype == "xyz"</Condition>
<TargetEndpoint>target2</TargetEndpoint>
</RouteRule>
These RouteRules will be evaluated in order.
Note that you probably want the bottom RouteRule to have no condition, which means it will always match. What happens when thetype does not equal "abc" or "xyz"? Assuming target1 is the default, your code would look like this:
<RouteRule name="routeToTarget2">
<Condition>thetype == "xyz"</Condition>
<TargetEndpoint>target2</TargetEndpoint>
</RouteRule>
<RouteRule name="routeToTarget1">
<TargetEndpoint>target1</TargetEndpoint>
</RouteRule>
If you are using the API Proxy Editor UI, then you can do the following:
(1) Choose New / New Resource from the API Proxy Editor toolbar.
You will then see this:
(2) For the input field, Optional Target URL, enter the target URL that corresponds to that resource.
This tool will then generate both a conditional flow for that resource to which you can optionally attach resource-specific policies.
This tool will also add the needed route rule, and your generated XML will look like this:
<ProxyEndpoint name="default">
<RouteRule name="Resource-1">
<Condition>(proxy.pathsuffix MatchesPath "/someResource") and (request.verb = "GET")</Condition>
<HTTPTargetConnection>
<URL>http://myAlternateEndpoint</URL>
</HTTPTargetConnection>
</RouteRule>
....

How to handle Apigee error case when query parameter checking in proxy

I have the following. The parameter "g" is allowed to be "on" or "off", otherwise go to an error policy. However, the exception case is never called. Instead, the "on" case is called if something that is not "on" or "off" is passed as "g". Why is that? Or, is there a better way of expressing this?
<PreFlow name="PreFlow">
<Request>
<Step>
<Condition>message.queryparam.g := "on"</Condition>
<Name>GOn</Name>
</Step>
<Step>
<Condition>message.queryparam.g := "off"</Condition>
<Name>GOff</Name>
</Step>
<Step>
<Condition>!((message.queryparam.g := "off") || (message.queryparam.g := "on"))</Condition>
<Name>GError</Name>
</Step>
</Request>
I just tested your conditions and they work properly. If the request has the following query parameter values:
g=on or g=ON, the GOn policy will execute.
g=off or g=OFF, the GOff policy will execute.
g={anythingelse}, the GError policy will execute.
The := operator is the equals case-insensitive operator. How are you determining that the conditions are not working? Using your example, I made each of the policies a RaiseFault with a different fault response payload. This allowed me to verify which policy was executed depending on the value of g.
I agree with Michael, the code as shown is correct.
Thinking about possible issues that could cause this code to not work as expected:
Make sure that the names are correct inside your GOn, GOff, and GError policies. (If you are working offline, the name of the file has nothing to do with which policy gets called.) For example, the outer element of the GOn policy should look something like
<AssignMessage name="GOn">
If GOn uses AssignMessage to modify message, you might blow away the g query parameter during a step, and your later checks might fail. If you are modifying the message, store message.queryparam.g into a different variable before you do your checks.
I would use the trace tool and a tool like Postman to see what is happening for each request. The trace should tell you the variables that have been checked and their values, and you might be able to see where you are going wrong.
If you have multiple conditional checks try using javascritp.In the java script check the various conditions and set flag.And in the flow based on the value of flag execute the required policy.But for the above instance ,as Michael pointed out , the conditions should work as expected.

Resources