Adding the additional logging helped. Looking at it now, it looks like it is working as coded:

9413847-9428572 BEGENING OF LOOP FOR: XAL465.1110.A0
9413847-9428572 START RECURSIVE
9421986-9428572 Has Value
9413847-9428572 BEGENING OF LOOP FOR: XAL465.1110.A1

The call for 9413847 is looping through all results of the query. It finds that 9421986 has a composition so it calls itself recursively. The call for 9421986 finds that it already has a value so it returns control to the 9413847 loop which continues iterating.

If you want all super and sub loops to quit as soon as any sub-loop finds "has value" then you will need to check for this condition inside the loop.

It's a bit hard to follow the output. I think things will become clearer if you add "mainArticle" and "article" to every WRITE statement, for example:

W !, $G(mainArticle),"-",$G(article)," Has Value"
...
W !, $G(mainArticle),"-",$G(article)," BEGENING OF LOOP FOR: "_rs.articleCode
...
W !, $G(mainArticle),"-",$G(article)," START RECURSIVE"
...
W !, $G(mainArticle),"-",$G(article)," END OF LOOP"

Hopefully this can save you some work. It uses a much larger chunk size (which is a multiple of 57) and works with or without CR/LFs (set the argument pAddCRLF):

Class Example.B64.Util Extends %RegisteredObject
{

/// Be cautious if changing CHUNKSIZE. Incorrect values could cause the resulting encoded data to be invalid.
/// It should always be a multiple of 57 and needs to be less than ~2.4MB when MAXSTRING is 3641144
Parameter CHUNKSIZE = 2097144;

ClassMethod B64EncodeStream(pStream As %Stream.Object, pAddCRLF As %Boolean = 0) As %Stream.Object
{
    set tEncodedStream=##class(%Stream.GlobalCharacter).%New()
    
    do pStream.Rewind()
    
    while ('pStream.AtEnd) {
        set tReadLen=..#CHUNKSIZE
        set tChunk=pStream.Read(.tReadLen)
        
        do tEncodedStream.Write($System.Encryption.Base64Encode(tChunk,'pAddCRLF))
        if (pAddCRLF && 'pStream.AtEnd) {
            do tEncodedStream.Write($c(13,10))
        }
    }
    
    do tEncodedStream.Rewind()
    
    quit tEncodedStream
}

}

My experience with Zebras was quite a few years ago, so this may or may not still apply... Using Zen reports at the time, the print server would end up rendering the label as a bitmap and sending that over to the Zebra. ZPL code to print an equivalent label was much smaller than a bitmap, so ZPL labels tended to print faster than those rendered by a report.

Ok, so the flow would look roughly like this:

  • The GenericService accepts an inbound REST request, populates a GenericMessage, and sends it to your business process
  • Business process extracts the JSON payload from the GenericMessage, and pulls out any relevant details needed for the call to Athena
  • Business process creates a new GenericMessage, populates any items needed by Athena, uses %SYS.OAuth2 (and the OAuth client profile you created) to request an OAuth token and adds it to the GenericMessage, and passes the new GenericMessage to the business operation.
  • Business operation makes the outbound REST call to Athena, and returns a new GenericMessage containing the response to your business process.
  • Business process extracts JSON payload from the GenericMessage, uses a transformation to create the payload required by your internal REST client.
  • Business process creates a new GenericMessage, populates it with the response payload, and returns it to the GenericService
  • GenericService returns response to REST client

For the outbound REST calls, I would typically create a custom operation class that calls methods in %SYS.OAuth2.* to fetch a token from the downstream system and then places that in the HTTP header.

If it's essential for you to avoid creating a custom class, you could call the %SYS.OAuth2 methods from a BPL and then add the token to the header fields in the EnsLib.HTTP.GenericMessage that you send to the GenericOperation.

You haven't said what needs to happen between the business service and business operation, so it's hard to discuss how everything fits together as you asked.

You'll want to configure the passthrough service to use "Standard Requests". This means REST requests will pass through a web server (IIS, Apache, etc) to get to IRIS:
https://docs.intersystems.com/irisforhealth20221/csp/docbook/DocBook.UI....

For TLS, you'll enable HTTPS on your web server.

And see this docs on enabling OAuth for web services:
https://docs.intersystems.com/irisforhealth20221/csp/docbook/DocBook.UI....