Announcement Announcement Module
Collapse
No announcement yet.
How can I implement a sleep before retrying... Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • How can I implement a sleep before retrying...

    Hi

    Below is my use case:

    I invoke an external svc that provides me the status of my job under execution. I've a channel configured for this in the spring config:

    Code:
    	<int:chain input-channel="ersSvc2erpSvcChannel">
    		<int:header-value-router header-name="RPT_TYPE_CODE">
    			<int:mapping value="ACT" channel="ACTpollerSvcReqMsgBuilderChannel" />
    		</int:header-value-router>
    	</int:chain>
    
    	<int:service-activator input-channel="ACTpollerSvcReqMsgBuilderChannel" 
    						   output-channel="pollerSvcSubmitSyncReqChannel" 
    						   ref="pollerSvcReqMsgBuilder" 
    						   method="getReportPollerSvcReq" />
    The response my external svc is recvd on a different channel:

    Code:
    	<int:chain input-channel="erpSvc2ersSvcChannel">
    		<int:header-value-router header-name="RPT_TYPE_CODE">
    			<int:mapping value="ACT" channel="ACTpollerSvcResMsgHandlerChannel" />
    		</int:header-value-router>
    	</int:chain>
    
    	<int:router input-channel="ACTpollerSvcResMsgHandlerChannel" 
    				expression="payload.messageBody.responseDetails.jobInfo[0].state.toUpperCase()">
    		<int:mapping value="SCHEDULED" channel="nullChannel" />Y
    		<int:mapping value="PENDING" channel="nullChannel" />Y
    		<int:mapping value="WAITING" channel="nullChannel" />Y
    		<int:mapping value="RUNNING" channel="nullChannel" />Y
    		<int:mapping value="SUCCEEDED" channel="nullChannel" />N
    		<int:mapping value="FAILED" channel="nullChannel" />B
    		<int:mapping value="CANCELLED" channel="nullChannel" />B
    		<int:mapping value="EXPIRED" channel="nullChannel" />B
    	</int:router>
    In the response payload, I get the status code of the Job.

    My requirement is, for few of these status codes, I need to retry invoking the external svc (i.e., I need to again put my message on "ersSvc2erpSvcChannel").
    However, I want to sleep for few millis before I put the message on the "ersSvc2erpSvcChannel" channel.

    Is there any way I can achieve this ?

    I tried thinking of using the "retryTemplate" with a "backOff" policy but then I've create a java class (service-activator) for it, hard-code (or put in some config file) the different status codes and need to explicitly throw an exception for the status codes I need to retry. Moreover, "retryTemplate" is going to invoke the "same" service-activator whereas I want my message to land on a different channel (i.e., need to invoke a different service-activator) for the retry usecase.

    I want to achieve my use case through spring config file itself so that I do not have to create any java class and embed the business logic I'm trying to achieve.

    Any suggestions will be highly appreciated.

    Best Regards
    LB

  • #2
    http://static.springsource.org/sprin...r.html#delayer

    Comment


    • #3
      However, if you want to pause the current thread, you could use a groovy script with Thread.sleep(100).

      Comment


      • #4
        So, if I understand correctly, to sleep under current thread, below configuration should be good ?


        Code:
        	<int:chain input-channel="erpSvc2ersSvcChannel">
        		<int:header-value-router header-name="RPT_TYPE_CODE">
        			<int:mapping value="ACT" channel="ACTpollerSvcResMsgHandlerChannel" />
        		</int:header-value-router>
        	</int:chain>
        
        	<int:router input-channel="ACTpollerSvcResMsgHandlerChannel" 
        				expression="payload.messageBody.responseDetails.jobInfo[0].state.toUpperCase()">
        		<int:mapping value="SCHEDULED" channel="ReportingServerEncyclopediaJobStatusRetryChannel" />
        		<int:mapping value="PENDING" channel="ReportingServerEncyclopediaJobStatusRetryChannel" />
        		<int:mapping value="WAITING" channel="ReportingServerEncyclopediaJobStatusRetryChannel" />
        		<int:mapping value="RUNNING" channel="ReportingServerEncyclopediaJobStatusRetryChannel" />
        		<int:mapping value="SUCCEEDED" channel="ReportingServerEncyclopediaJobStatusCMPChannel" />
        		<int:mapping value="FAILED" channel="ReportingServerEncyclopediaJobStatusFLDChannel" />
        		<int:mapping value="CANCELLED" channel="ReportingServerEncyclopediaJobStatusFLDChannel" />
        		<int:mapping value="EXPIRED" channel="ReportingServerEncyclopediaJobStatusFLDChannel" />
        	</int:router>
        Code:
        	
        <int:service-activator input-channel="ReportingServerEncyclopediaJobStatusRetryChannel" output-channel="resMsgHandlerOutputChannel">
        		<int:header-enricher>
        			<int:header name="RPT_SERVER_JOB_STATUS_RETRY_FLAG" expression="Y"/>
        		</int:header-enricher>
        		<int-groovy:script>
             			<![CDATA[
        		     		Thread.sleep(1000);
        			]]>
        		</int-groovy:script>
        	</int:service-activator>
        
        	<int:service-activator input-channel="ReportingServerEncyclopediaJobStatusCMPChannel" output-channel="resMsgHandlerOutputChannel">
        		<int:header-enricher>
        			<int:header name="RPT_SERVER_JOB_STATUS_RETRY_FLAG" expression="N"/>
        		</int:header-enricher>
        	</int:service-activator>
        
        	<int:service-activator input-channel="ReportingServerEncyclopediaJobStatusFLDChannel" output-channel="resMsgHandlerOutputChannel">
        		<int:header-enricher>
        			<int:header name="RPT_SERVER_JOB_STATUS_RETRY_FLAG" expression="B"/>
        		</int:header-enricher>
        	</int:service-activator>

        Code:
        	
        <int:header-value-router input-channel="resMsgHandlerOutputChannel" header-name="RPT_TYPE_CODE">
        		<int:mapping value="ACT" channel="ACTpollerSvcResMsgHandlerOutputChannel" />
        	</int:header-value-router>
        
        	<int:bridge input-channel="ACTpollerSvcResMsgHandlerOutputChannel" 
        				output-channel="COMMONpollerSvcResMsgHandlerOutputChannel" />
        
        	<int:header-value-router input-channel="COMMONpollerSvcResMsgHandlerOutputChannel" header-name="RPT_SERVER_JOB_STATUS_RETRY_FLAG">
        		<int:mapping value="Y" channel="ersSvc2erpSvcChannel" /> <!-- this will retry the job status -->
        		<int:mapping value="N" channel="ersSvc2TrfSvcChannel" /> <!-- this will process message further -->
        		<int:mapping value="B" channel="jobFLDChannel" /> <!-- this will gracefully exit the execution flow -->
        	</int:header-value-router>
        Also another quick question, is it syntactically correct to use both <int-groovy:script> and <int:header-enricher> child elements under one single parent <int:service-activator> element ? In other words, below configuration is correct syntax for service-activator ? OR I need to use a <chain> for it ?

        Code:
        <int:service-activator input-channel="ReportingServerEncyclopediaJobStatusRetryChannel" output-channel="resMsgHandlerOutputChannel">
        		<int:header-enricher>
        			<int:header name="RPT_SERVER_JOB_STATUS_RETRY_FLAG" expression="Y"/>
        		</int:header-enricher>
        		<int-groovy:script>
             			<![CDATA[
        		     		Thread.sleep(1000);
        			]]>
        		</int-groovy:script>
        	</int:service-activator>
        Thanks for the feedback.

        Best Regards
        LB
        Last edited by lbvirgo; Jul 16th, 2013, 01:21 PM.

        Comment


        • #5
          You can't put a <header-enricher/> inside a <service-activator/>.

          A header-enricher is either a top-level element (or it can be inside a <chain/>).

          Are you not using an IDE (STS or IntelliJ)?? Those IDEs will validate your XML while you are developing.

          For the sleeps, the script needs to return a value, so you need

          Code:
          		<int-groovy:script>
               			<![CDATA[
          		     		Thread.sleep(1000)
          		     		payload
          			]]>
          		</int-groovy:script>
          You don't need semicolons in groovy and the 'payload' at the end means return the payload.

          Comment


          • #6
            Thanks for responding Gary.

            You can't put a <header-enricher/> inside a <service-activator/>
            Even a plain <int:header> cannot be embedded inside a <service-activator> ? i.e., even below is not possible :

            Code:
            	<int:service-activator input-channel="ReportingServerEncyclopediaJobStatusCMPChannel" output-channel="resMsgHandlerOutputChannel">
            			<int:header name="RPT_SERVER_JOB_STATUS_RETRY_FLAG" expression="N"/>
            	</int:service-activator>
            If its not possible then to me its kind of a overkill to go for a chain just to have an additional header embedded.
            I remember in one of my other config using <int:header> inside the gateway <int:method> and it works fine. I believe then <int:header> should work here as well.


            Are you not using an IDE (STS or IntelliJ)??
            No. I'm using NTS IDE. Also I'm not sure if I've the required permissions to download STS or IntelliJ.


            For the sleeps, the script needs to return a value
            Thanks for pointing it out. However just want to know if the overall configuration that I mentioned above captures the logic that I'm trying to achieve ?

            Best Regards
            LB
            Last edited by lbvirgo; Jul 16th, 2013, 01:49 PM.

            Comment


            • #7
              Even a plain <int:header> cannot be embedded inside a <service-activator>
              Correct; the proper top level element is a <header-enricher/>, which can add one or more headers.

              Enriching headers is a separate concern to invoking a service but, in any case in that example, your service activator is not actually doing anything, so just change it to a header-enricher.

              Code:
              <int:header-enricher input-channel="ReportingServerEncyclopediaJobStatusCMPChannel" output-channel="resMsgHandlerOutputChannel">
              			<int:header name="RPT_SERVER_JOB_STATUS_RETRY_FLAG" expression="N"/>
              </int:header-enricher>
              If you want to combine invoking some service as well as adding headers, you have two choices

              - use a chain and add the <header-enricher/> right after the service activator.
              - make your service message-aware

              Code:
              <int:service-activator input-channel="ReportingServerEncyclopediaJobStatusCMPChannel" output-channel="resMsgHandlerOutputChannel" 
                   ref="myService" method="foo" />
              
              <bean id="myService" class="foo.MyService" />
              
              public class MyService {
              
                  public Message<?> foo(SomeObject payload) {
                      // do some work
                      return MessageBuilder.withPayload(newPayload).setHeader("foo", "bar").build();
                  }
              }
              The framework will take care of merging the inbound headers with your new header.

              Comment

              Working...
              X