WxResilience: Robust services and standardized logging out-of-the-box!

Introduction

WxResilience is a free webMethods IntegrationServer package for implementing resilient and robust services using a standardized logging out-of-the-box:

Success:

2023-03-17 15:56:40 CET [ISP.0090.0004I] (tid=1324) WxResilienceDemoInvokeChain -- Processing started for |service:wx.resilienceDemoInvokeChain.pub:test_top|callerType:HTTP|callerId:Designer|contextID:62a2317e-e579-4732-acad-85f5817eedb2|correlationID:48e13d1a-abcc-4870-b755-2dd099c2c374| 
2023-03-17 15:56:40 CET [ISP.0090.0004I] (tid=1324) WxResilienceDemoInvokeChain -- Processing finished for |service:wx.resilienceDemoInvokeChain.pub:test_top|contextID:62a2317e-e579-4732-acad-85f5817eedb2|status:SUCCESS|duration:0.088|correlationID:48e13d1a-abcc-4870-b755-2dd099c2c374|

Error:

2023-03-17 15:59:11 CET [ISP.0090.0004I] (tid=1324) WxResilienceDemoInvokeChain -- Processing started for |service:wx.resilienceDemoInvokeChain.pub:test_topException|callerType:HTTP|callerId:Designer|contextID:bfd726c5-7e8e-47ee-8804-da2143562673|correlationID:8ade1933-fa62-4c89-a5ba-8ef95da6b3cd| 
2023-03-17 15:59:11 CET [ISP.0090.0004E] (tid=1324) WxResilienceProcessor -- Handle error 
2023-03-17 15:59:11 CET [ISP.0090.0004E] (tid=1324) WxResilienceDemoInvokeChain -- Error occurred:

Message: “[ISS.0086.9249] Missing Parameter: inString”
Type: “com.wm.app.b2b.server.ServiceException”

Caller type: HTTP

Location:
Top service error: “wx.resilienceDemoInvokeChain.pub:test_topException”, FlowStep: “n.a.”
Handled service error: “wx.resilienceDemoInvokeChain.pub:test_topException”, FlowStep: “n.a.”
Application service error: “wx.resilienceDemoInvokeChain.impl:subException”, FlowStep: “/0”
Root service error: “pub.string:tokenize”, FlowStep: “n.a.”

Exception handling ID: WxResilience.global.001
Retry count: 0
Max retry attempts: 0
Exception to be thrown: FATAL

Full call stack:
“wx.resilienceDemoInvokeChain.pub:test_topException”, FlowStep: “”
“wx.resilienceDemoInvokeChain.impl:subException”, FlowStep: “/0”
“pub.string:tokenize”, FlowStep: “”

|correlationID:8ade1933-fa62-4c89-a5ba-8ef95da6b3cd|
2023-03-17 15:59:11 CET [ISP.0090.0004E] (tid=1324) WxResilienceDemoInvokeChain – Processing canceled for |service:wx.resilienceDemoInvokeChain.pub:test_topException|contextID:bfd726c5-7e8e-47ee-8804-da2143562673|status:CANCELLED|duration:0.295|error:[ISS.0086.9249] Missing Parameter: inString|correlationID:8ade1933-fa62-4c89-a5ba-8ef95da6b3cd|
2023-03-17 15:59:11 CET [ISP.0090.0004W] (tid=1324) WxResilienceDemoInvokeChain – Rethrow error as FATAL: [ISS.0086.9249] Missing Parameter: inString|correlationID:8ade1933-fa62-4c89-a5ba-8ef95da6b3cd|

Pre-requisite

This package is developed and tested in wM10.3 (IS), 10.11 (IS&MSR) and 10.15 (IS) (Windows). It is designed for usage together with the official packages WxConfig (or the free alternative https://tech.forums.softwareag.com/t/wxconfiglight/268738) and optionally together with packages for logging like WxLog, WxLog2, WxLog4j2, WxSplunk or WxLoki.

Details

How to use

There are two options to use WxResilience in your top level services:

  1. Automatically from InvokeChain (without any change of application code) - suggested for existing IS users
  2. Per code in your top-level-services - alternative for new IS users

InvokeChain: All service invocations in IS are executed at the end of an InvokeChain. Part of that InvokeChain are e.g. the ACLManager or the AuditLogManager which envelope the real invocation and add some additional features. You can register your own “processor” in that InvokeChain by using the Java API of the IS.

The two options in detail:

  1. Set the key
    wxconfig-.cnf/invokeChainProcessor.enabled=true
    and run the startup service of WxResilience. It will run the predefined services (see below) around of your top-level-service as it is registered in the InvokeChain of IntegrationServer before your top-level-service is invoked. This option can be choosen if WxResilience is introduced at once on a existing system. It will immediately work for all top-level-services and can be deactivated or configured. Restrictions: The InvokeChain-technique is not working during debugging!
  2. Implement try-catch-blocks in your top level services using the predefined services directly (see below). This option provides you more control for which services and how it will work. But this option requires code changes. To see the suggestion how to build a resilient service take a look on: WxResilienceDemoFlow/wx.resilienceDemoFlow.pub:test_top:

Try-Catch

It is possible to mix both options as there is a check not to run the services twice for a top-level-service call.

Predefined errorhandling

WxResilience contains in WxResilience/config/ExceptionHandling.xml a bunch of knowledge about possible exceptions and how to treat them. The goal is that WxResilience can decide for you out-of-the-box if it make sense to retry a service or not (retry in case of transient errors but avoid blocking messages). This logic is implemented as part of wx.resilience.pub.resilience:handleError.

Special features

Customized Logging

The logmessages created by WxResilience can be redirected/duplicated if you provide a service following the signature of debugLog and configure the service in wxconfig-<env>:
# Log service for wx.resilience.impl.log.wrapper:logDebugLog (IS server.log)
logging.service.env=wx.resilience.impl.log.wrapper:logDebugLog
# Log service for WxLog4j2 (log4j2)
#logging.service.env=wx.resilience.impl.log.wrapper:logWxLog4j2
# Log service for WxLog (Logback)
#logging.service.env=wx.resilience.impl.log.wrapper:logWxLog
# Log service for WxLog2 (log4j)
#logging.service.env=wx.resilience.impl.log.wrapper:logWxLog2
# Log service for WxSplunk
logging.service.env=wx.resilience.impl.log.wrapper:logWxSplunk

Furthermore, you can use that infrastructure for your additional logging if you log per this service:
wx.resilience.pub.log:log

Interaction with external clients and End-to-End-Monitoring

WxResilience is designed for tracing data from external clients together with End-to-End-Monitoring (E2EM). Therefore WxResilience can handle a correlationId from clients and uses setCustomContextId: The service wx.resilience.pub.resilience:preProcessForTopLevelService is reading the JMSCorrelationID (JMS) respectively the X-Correlation-ID (HTTP) from callers, stores it in wxMetaData/correlationId and use it for setCustomContextID (visible in Monitor/E2EM). Finally, these IDs are forwarded via JMS and HTTP if you use the related wrapper services in WxResilience or automatically, if you use the InvokeChain. As result, you can follow your data over different top-level-services:

And you can identify this data in E2EM:

Optional usage of "wxMetaData" for enhanced logging

If you call the predefined standard service of WxResilience while you have "wxMetaData" on the pipeline you can benefit from enhanced logging:

2023-03-17 16:14:29 CET [ISP.0090.0004OFF] (tid=1108) WxResilienceDemoFlow -- My personal message|source:mySource|destination:myDestination|type:myType|correlationID:43|
CP:|myKey:myValue| 
![wxMetaData|431x203](upload://1rENGkxYECJy9GzeZGtIzt9OPG4.png)

If you already using something like metaData you can inject your metaData to WxResilience by providing a conversion service:


metaData.conversion.service.ifcname=wx.resilienceDemoInvokeChain.pub
metaData.conversion.service.svcname=mapMyMetaDataToWxMetaData

Break endless loop

If a JMSMessage from a trigger is stuck in an endless loop (and you are using wxMetaData), you can break this loop per temporary key in wxconfig.cnf:


break.retry.loop.for.id=b86b6639-b026-49ca-ad01-3d19810c3cda

DocumentDiscardedException

Sometimes there is the need to drop a message within your code (maybe deep in a sub service). To do that easily and safely you can invoke the service without developing any other code, exits, or whatever:

wx.resilience.pub.resilience:throwDocumentDiscardedException

WxResilience will catch this error, write a proper logging, and do not rethrow any error.

2023-03-17 16:17:11 CET [ISP.0090.0004W] (tid=1108) WxResilienceDemoInvokeChain -- Processing discarded for |service:wx.resilienceDemoInvokeChain.pub:test_DocumentDiscardedException|contextID:e4de5b07-ffc4-4daf-93f3-b133c6967222|status:DISCARDED|duration:0.049|error:garbage!|type:t|correlationID:cb9092b8-5aba-4023-a43d-02d9e6d4abd2|
CP:|testId:42| 

Status messages

WxResilience supports sending status messages back to the source of your message in case of a (non-transient) error. These status messages are published on a special topic. You can use that in order to inform the original source that its message was aborted (if you have specified the source in wxMetaData).

Finally, you can allow the external systems to send such messages by their own as they are sent in JSON (and not IData). In that case, the external system A can send a message over IS to the external system B. System B can acknowledge that by a status “Completed”. System A can receive and process that. If the message is failing in IS system A would receive a status “Failed” from IS using the same technique.


{
	"wxMessage": {
		"wxMetaData": {
			"creationTimestamp": "2023-03-17T16:18:25.636+0100",
			"correlationID": "cfa5db37-4614-41d5-9267-a21413cde32e",
			"tracingHops": [
				{
					"sender": {
						"sendDate": "2023-03-17T16:19:09.069+0100",
						"host": "daeigcs62184.eur.ad.sag",
						"primaryPort": "5555"
					},
					"receiver": {
						"connectionAliasName": "DEFAULT_IS_JMS_CONNECTION",
						"destinationName": "StatusTopic",
						"destinationType": "TOPIC"
					}
				}
			],
			"uuid": "daac7eb6-f6fc-4f8d-930a-436b39c36ee5",
			"type": "status",
			"source": "destSystem",
			"destination": "sourceSystem",
			"customProperties": [
				{
					"key": "refId",
					"value": "42"
				},
				{
					"key": "STATUS_ORIGINAL_TYPE",
					"value": "order"
				}
			]
		},
		"payload": {
			"message": "Your messages is completely processed!",
			"type": "Completed",
			"code": "YOUR_SUCCESS_CODE_001",
			"timestamp": "2023-03-17T16:18:39.805+0100",
			"host": "daeigcs62184.eur.ad.sag",
			"port": "5555",
			"transport": {
				"protocol": "http",
				"subprotocol": "HTTP",
				"http": {
					"requestUrl": "/wm-message",
					"method": "POST",
					"requestHdrs": {
						"User-Agent": "webMethods",
						"Host": "localhost:5555",
						"Authorization": "Basic QWRtaW5pc3RyYXRvcjpQYXNzdzByZEAxMjM0",
						"Cookie": "ssnid=6a457e291fda4d8ca519c088931948a1",
						"Content-Type": "application/x-wmidatabin",
						"Accept-Language": "en-US",
						"Content-Length": "714"
					},
					"ipInfo": {
						"localIp": "127.0.0.1",
						"localPort": "5555",
						"remoteIp": "127.0.0.1",
						"remotePort": "51322"
					}
				}
			}
		}
	}
}

Next steps

It is planned to send status messages automatically in case of a successful retry or resubmit.

Useful links

Disclaimer

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2 Likes