go to post Menno Voerman · Aug 9, 2023 Hi Pietro, Not sure if this will help you but I written a retry mechanisme in the BO with 2 additional settings MaxRetries and RetryWaitSeconds. See code below: Class BO.Rest.PostBodyHeaderAuth Extends EnsLib.REST.Operation { Parameter ADAPTER = "EnsLib.HTTP.OutboundAdapter"; Parameter INVOCATION = "Queue"; Property HeaderName As %String(MAXLEN = 1000) [ InitialExpression = "Authorization", Required ]; Property HeaderValue As %String(MAXLEN = 10000) [ InitialExpression = "Bearer", Required ]; Property UseSSL As %Integer [ InitialExpression = 1, Required ]; Property MaxRetries As %Integer [ InitialExpression = 3, Required ]; Property RetryWaitSeconds As %Integer [ InitialExpression = 300, Required ]; Property ContentType As %String(MAXLEN = 300) [ InitialExpression = "application/json; charset=utf-8", Required ]; Parameter SETTINGS = "HeaderName:Auth,HeaderValue:Auth,MaxRetries:Retry,RetryWaitSeconds:Retry,UseSSL:Connection,ContentType:ContentType"; Method PostBodyData(pRequest As BO.Rest.PostBodyHeaderAuth.PostBodyHeaderAuthReq, Output pResponse As BO.Rest.PostBodyHeaderAuth.PostBodyHeaderAuthResp) As %Status { Set tSc = $$$OK Set tCounter = 0 While (tCounter <= ..MaxRetries) { //Create a new %Net.HttpRequest Set tHttpRequest = ##class(%Net.HttpRequest).%New() //Get the serversetting from the Adapter Set tHttpRequest.Server = ..Adapter.HTTPServer Set tHttpRequest.Port = ..Adapter.HTTPPort //Set Content-Type Set tHttpRequest.ContentType = ..ContentType //Set Body from Request Object Do tHttpRequest.EntityBody.Write(pRequest.Body) // Set Https Flag If (..UseSSL = 1) { Set tHttpRequest.Https = 1 Set tHttpRequest.SSLConfiguration = ..Adapter.SSLConfig } Else { Set tHttpRequest.Https = 0 } //Set the Header value for Authentication If ($LENGTH(pRequest.HeaderValue) > 0) { Set tSc = tHttpRequest.SetHeader(..HeaderName, pRequest.HeaderValue) } Else { Set tSc = tHttpRequest.SetHeader(..HeaderName, ..HeaderValue) } //Set Custom Timeouts from Adapter Set tHttpRequest.WriteTimeout = ..Adapter.WriteTimeout Set tHttpRequest.Timeout = ..Adapter.ResponseTimeout Set tHttpRequest.OpenTimeout = ..Adapter.ConnectTimeout If ($LENGTH(pRequest.Url) > 0) { Set tUrl = pRequest.Url } Else { Set tUrl = ..Adapter.URL } //Create a trace with the complete url $$$TRACE(..Adapter.HTTPServer_"/"_tUrl) //Do the post call Set tSc = tHttpRequest.Post(tUrl) //Create the tHttpResponse object #dim tHttpResponse As %Net.HttpResponse //Set the response object Set tHttpResponse = tHttpRequest.HttpResponse //If an technical error has occured If ($$$ISERR(tSc)) { $$$TRACE("Error:"_$System.Status.GetErrorText(tSc)) } ElseIf ('$IsObject(tHttpResponse)) { $$$TRACE("Invalid HTTP Response Object") Set tSc=$$$ERROR($$$EnsErrGeneral, "Invalid HTTP Response Object.") } Else { ;Build Operation Response Set pResponse = ##class(BO.Rest.PostBodyHeaderAuth.PostBodyHeaderAuthResp).%New() Set pResponse.HTTPStatusCode = tHttpResponse.StatusCode Set pResponse.HTTPStatusLine = tHttpResponse.StatusLine ;Check the HTTPStatusCode Set tSuccess = ##class(Util.Functions).IsSuccess(tHttpResponse.StatusCode) If (tSuccess) { Set tCounter = ..MaxRetries + 1 Do tHttpResponse.Data.Rewind() Set pResponse.HTTPResponseData = tHttpResponse.Data } Else { $$$TRACE("An error HTTP code has been received. HTTPSCode="_tHttpResponse.StatusCode) Try { Do tHttpResponse.Data.Rewind() Set pResponse.HTTPResponseData = tHttpResponse.Data } Catch exception {} } } Set tCounter = tCounter+1 If (tCounter <= ..MaxRetries) { $$$TRACE("Retry: "_tCounter_". Wait for "_..RetryWaitSeconds_" seconds") HANG ..RetryWaitSeconds } } return tSc } }
go to post Menno Voerman · Jun 29, 2023 Hi Andy, I would say it should be enough to set indeed the Windows Service to manual/disabled during the maintenance: If youre in an mirror situation you could also disable the ISCAgent service, but I would say that the node will never switch because the other service is not up and running:
go to post Menno Voerman · Oct 25, 2021 Hi All, The problem is in HS.FHIRServer.RestHandler Class HS.FHIRServer.HC.FHIRInteropAdapter Extends HS.FHIRServer.RestHandler { Parameter isInteropAdapter As %Boolean = 1; Parameter ServiceConfigName As %String = "InteropService"; } For some reason its not allowed to send the bearer token with the unauthenticated application: // Access token present on unsecure CSP request is invalid. Otherwise, if access // token found on secure CSP request then add to FHIR request AdditionalInfo for // later evaluation by the FHIR service. If '%request.Secure { If ($ZConvert($Piece(%request.GetCgiEnv("HTTP_AUTHORIZATION")," ",1),"U") = "BEARER") || ($Get(%request.Data("access_token",1)) '= "") { Set %response.Status = ..#HTTP401UNAUTHORIZED Return $$$OK } Set accessToken = "" } Else { // InterSystems FHIRServer policy is to NOT allow passing access token in the // request URL or form encoded body (either can be found in %request.Data). If $Get(%request.Data("access_token",1)) '= "" { Set %response.Status = ..#HTTP401UNAUTHORIZED Return $$$OK } Set accessToken = ##class(%SYS.OAuth2.AccessToken).GetAccessTokenFromRequest(.tSC) $$$ThrowOnError(tSC) If accessToken '= "" { Do tRequest.AdditionalInfo.SetAt(accessToken, "USER:OAuthToken") Do tRequest.AdditionalInfo.SetAt(hsrestconfig.OAuthClientName, "USER:OAuthClient") } } We're gonna discuss the issue with intersystems but it looks like we need custom programming to make this situation work in the new HC version.
go to post Menno Voerman · Sep 21, 2021 Thank you @Alister Pino and @Julius Kavay for your help. In this scenario see the final solution below: ClassMethod MergeDynamicObjects(ObjComplete As %Library.DynamicObject, ObjAddendum As %Library.DynamicObject) [ Final ] { Set obj1 = ObjComplete.%Get("OptOuts") Set obj2 = ObjAddendum.%Get("OptOuts") Set OptOuts2Iter = obj2.%GetIterator() While OptOuts2Iter.%GetNext(.key , .value ) { Do obj1.%Push(value) } return ObjComplete }