Get hands-on experience with 20+ free Google Cloud products and $300 in free credit for new customers.

Fault rule conditional policies failing to execute

Not applicable

Our proxy fault rules (simplified) look like this:

    <FaultRules>
        <FaultRule name="api_key_faults">
            <Step>
                <Name>fault_invalid_key</Name>
                <Condition>(fault.name = "InvalidApiKey")</Condition>
            </Step>
            <Step>
                <Name>fault_missing_key</Name>
                <Condition>(fault.name = "FailedToResolveAPIKey")</Condition>
            </Step>
        </FaultRule>
        <FaultRule name="no_routes_matched_rule">
            <Step>
                <Name>fault_no_route</Name>
            </Step>
            <Condition>(fault.name = "NoRoutesMatched" || fault.name = "RouteFailed" || fault.name = "NotFound")</Condition>
        </FaultRule>
        <FaultRule name="quota_rule">
            <Step>
                <Name>fault_developer_quota_exceeded</Name>
                <Condition>(ratelimit.check_developer_quota.exceed.count > 0)</Condition>
            </Step>
            <Step>
                <Name>fault_global_quota_exceeded</Name>
                <Condition>(ratelimit.check_global_quota.exceed.count > 0)</Condition>
            </Step>
            <Condition>(fault.name = "QuotaViolation")</Condition>
        </FaultRule>
        <FaultRule name="spike_arrest">
            <Step>
                <Name>fault_spike_arrest</Name>
                <Condition>spikearrest.spike_protection.failed = "true"</Condition>
            </Step>
            <Step>
                <Name>fault_revalidate_spike_arrest</Name>
                <Condition>(spikearrest.revalidate_spike_protection.failed = "true")</Condition>
            </Step>
            <Condition>(fault.name = "SpikeArrestViolation")</Condition>
        </FaultRule>
    </FaultRules>
    <DefaultFaultRule name="default_fault_rule">
        <Step>
            <Name>fault_generic_error</Name>
            <Condition>(wf.fault_assigned != "true")</Condition>
        </Step>
        <Step>
            <Name>calculate_response_headers</Name>
        </Step>
        <AlwaysEnforce>true</AlwaysEnforce>
    </DefaultFaultRule>

Note that every fault_xxxx policy sets (wf.fault_assigned = "true") so if any error has been assigned the fault_generic_error policy will not execute. This works.

As described here, conditions can go inside or outside the STEP tag.. I'm seeing a couple of issues:

If I move the CONDITION tag from outside to inside the STEP tag on "no_routes_matched_rule", then *all* error fault conditions fail and the fault_generic_error executes. Since there is only one step, the execution behaviour would seem that it should not change, not to mention fail.

The same failure happens if I remove from "spike_arrest" the outer condition (fault.name = "SpikeArrestViolation") that is actually not needed.

Additionally, in the existing form, "spike_arrest" never executes at least "fault_revalidate_spike_arrest", even though the condition appears to be correct.

Note that the "quota_rule" above seems to execute as desired, so its basic structure of nested conditionals seems to work.

I suspect that this is a bug, otherwise, what is wrong here?

Thanks, George

Solved Solved
2 31 4,440
2 ACCEPTED SOLUTIONS

@Floyd Jones- I think I recently observed the Fault Rules are evaluated Bottom to Top in the ProxyEndpoint, but Top to Bottom in the TargetEndpoint. Might be worth double checking!

View solution in original post

@Floyd Jones, @Sean Davis

I have confirmed that this is weirdly true.

I added the following to both proxy and target endpoint FaultRules and observed the test flow in the UI and in trace downloads.

<FaultRule name="raise-fault-1">
    <Condition>(fault.name = "RaiseFault")</Condition>
    <Step>
        <FaultRules/>
        <Name>Assign-Message-Raise-Fault-1</Name>
    </Step>
</FaultRule>
<FaultRule name="raise-fault-2">
    <Condition>(fault.name = "RaiseFault") and ("fault.name" = "RaiseFault")</Condition>
    <Step>
        <FaultRules/>
        <Name>Assign-Message-Raise-Fault-2</Name>
    </Step>
</FaultRule>
<FaultRule name="raise-fault-3">
    <Condition>(fault.name = "RaiseFault") and ("fault.name" = "RaiseFault") and ("fault.name" = "RaiseFault")</Condition>
    <Step>
        <FaultRules/>
        <Name>Assign-Message-Raise-Fault-3</Name>
    </Step>
</FaultRule>

In the proxy trace download I see:

    <Point id="Condition">
        <DebugInfo>
            <Timestamp>02-08-16 14:11:24:763</Timestamp>
            <Properties>
                <Property name="ExpressionResult">false</Property>
                <Property name="Expression">((fault.name equals "RaiseFault") and (("fault.name" equals "RaiseFault") and ("fault.name" equals "RaiseFault")))</Property>
                <Property name="Tree">FAULT_raise-fault-3</Property>
            </Properties>
        </DebugInfo>
        <VariableAccess>
            <Get value="InvalidApiKey" name="fault.name"/>
        </VariableAccess>
    </Point>
    <Point id="Condition">
        <DebugInfo>
            <Timestamp>02-08-16 14:11:24:763</Timestamp>
            <Properties>
                <Property name="ExpressionResult">false</Property>
                <Property name="Expression">((fault.name equals "RaiseFault") and ("fault.name" equals "RaiseFault"))</Property>
                <Property name="Tree">FAULT_raise-fault-2</Property>
            </Properties>
        </DebugInfo>
        <VariableAccess>
            <Get value="InvalidApiKey" name="fault.name"/>
        </VariableAccess>
    </Point>
    <Point id="Condition">
        <DebugInfo>
            <Timestamp>02-08-16 14:11:24:763</Timestamp>
            <Properties>
                <Property name="ExpressionResult">false</Property>
                <Property name="Expression">(fault.name equals "RaiseFault")</Property>
                <Property name="Tree">FAULT_raise-fault-1</Property>
            </Properties>
        </DebugInfo>
        <VariableAccess>
            <Get value="InvalidApiKey" name="fault.name"/>
        </VariableAccess>
    </Point>

In the target trace download I see:

<Point id="Condition">
        <DebugInfo>
            <Timestamp>02-08-16 14:11:41:101</Timestamp>
            <Properties>
                <Property name="ExpressionResult">false</Property>
                <Property name="Expression">(fault.name equals "RaiseFault")</Property>
                <Property name="Tree">FAULT_raise-fault-1</Property>
            </Properties>
        </DebugInfo>
        <VariableAccess>
            <Get value="ErrorResponseCode" name="fault.name"/>
        </VariableAccess>
    </Point>
    <Point id="Condition">
        <DebugInfo>
            <Timestamp>02-08-16 14:11:41:101</Timestamp>
            <Properties>
                <Property name="ExpressionResult">false</Property>
                <Property name="Expression">((fault.name equals "RaiseFault") and ("fault.name" equals "RaiseFault"))</Property>
                <Property name="Tree">FAULT_raise-fault-2</Property>
            </Properties>
        </DebugInfo>
        <VariableAccess>
            <Get value="ErrorResponseCode" name="fault.name"/>
        </VariableAccess>
    </Point>
    <Point id="Condition">
        <DebugInfo>
            <Timestamp>02-08-16 14:11:41:101</Timestamp>
            <Properties>
                <Property name="ExpressionResult">false</Property>
                <Property name="Expression">((fault.name equals "RaiseFault") and (("fault.name" equals "RaiseFault") and ("fault.name" equals "RaiseFault")))</Property>
                <Property name="Tree">FAULT_raise-fault-3</Property>
            </Properties>
        </DebugInfo>

View solution in original post

31 REPLIES 31