There are a few issues with this code, but the biggest one is that you've created a clone and should be modifying the clone (pOutput) exclusively. However, you're still calling SetValueAt() against a segment pulled from pRequest.

The above notwithstanding, you're still sending the original unchanged message object (pRequest) to the target operation with the SendRequestAsync() call.

Fundamentally, you should:

  1. Create a clone of the request object pRequest (i.e. pOutput)
  2. Modify the clone, which is a mutable copy of the original message
  3. Send the modified clone (pOutput) to the target operation

The code sample you've provided above is pulling the OBX segment from pRequest, not the clone. pRequest is immutable so you can't make changes to it. You should be using the pOutput object for your SetValueAt() calls, and since it's a clone you can use it for the GetValueAt() calls as well.

I provided pretty much everything you need to do this via a DTL in your other post on this subject. If you're worried about keeping things simple for ongoing support, the DTL solution is likely the better option.

A couple of thoughts ...

  1. In my experience, the pool of resources that can build complex integrations using the Health Connect GUI is an order of magnitude larger than those that can do the same in pure ObjectScript. The rarer the resource, the more it costs.
  2. I've also found that some of those that have used ObjectScript as a method to enhance/alter the behavior of production components have implemented "private" methods or relied on undocumented behavior that has the potential to change or become deprecated, requiring extensive testing and possibly re-coding when upgrading.

You can do this by creating a collection object in a code block, and iterate over the comma-separated string to populate it:

 Set tArray = ##class(%ArrayOfDataTypes).%New()
 For i = 1:1:$LENGTH(LookupVal,",")
 {
     Do tArray.SetAt($PIECE(LookupVal,",",i),i)
 }

You can now iterate over the collection variable in the for each action:

Looks like HealthConnect/IRIS for Health doesn't supply ISO-8859-4 ("Northern European"), or its successor ISO-8859-10. You can try forcing other character sets by preceding them with an exclamation point in the operation's Default Char Encoding property, but there may be characters that translate incorrectly:

Here's how I would approach this using a DTL ...

  1. Create a counter variable to hold the number of occurrences of "Item Number:"
  2. Use a for each action to iterate over the OBX segments
  3. In the for each, create an if action that checks for the presence of "Item Number:" in OBX:5 (using ..Contains())
  4. If the action is true, increment the counter variable

Example:

On completion of the for each, you should have a value that indicates the presence of more than one "Item Number." Next, update the OBXs:

  1. Create another counter variable to track occurrences of "Item Number" to be used for comparison
  2. Add another for each action to perform the modifications to the OBX segments
  3. Use the $REPLACE() or ..Replace() functions to replace "REASON FOR REQUEST:" in each OBX:5 with an empty string
  4. Add an if action to check the OBX:5 field for "Item Number:"; increment the new counter variable if found
  5. Add an if action to evaluate the new counter variable against the original; if it's less than the original, add a line break (not actual $C(13)/$C(10) characters, but escaped representation such as \.br\ or \X0D\\X0A\; likely vendor-dependent)

Example:

Likely significantly faster:


SELECT COUNT(DISTINCT SessionId)
  FROM Ens.MessageHeader
  WHERE ID >= (SELECT TOP 1 ID FROM Ens.MessageHeader WHERE TimeCreated >='2025-02-01 00:00:00.000' ORDER BY TimeCreated ASC)
    AND ID <= (SELECT TOP 1 ID FROM Ens.MessageHeader WHERE TimeCreated <='2025-02-28 23:59:59.999' ORDER BY TimeCreated DESC)

In my crude and hasty benchmarking, twice as fast on a sampling of  2.7M message headers.

You can suspend the task via either ObjectScript or SQL.

Assuming you know the Task ID, and using 1001 as an example:

Set tsk = ##class(%SYS.Task).%OpenId(1001)
Set tsk.Suspended = 1
Do tsk.%Save()

or

Do ##class(%SYS.Task).Suspend(1001,1)

Resume the task with

Do ##class(%SYS.Task).Resume(1001)

Via SQL:

UPDATE %SYS.Task SET Suspended = 1 WHERE ID = 1001

or

UPDATE %SYS.Task SET Suspended = 1 WHERE TaskClass = 'Sample.Util.CreateTask'

Set Suspended to 0 to re-enable the task.

Something like this should do the trick:

ClassMethod GetConnectionStatus(pItemName As %String, ByRef pStatus As %String, ByRef pState As %String) As %Status [ Language = objectscript ]
{
	Set tStatement = ##class(%SQL.Statement).%New()
	Set tSC = tStatement.%PrepareClassQuery("Ens.Util.Statistics","EnumerateJobStatus")
	Return:$$$ISERR(tSC) tSC
	Set tRS = tStatement.%Execute(pItemName)
	If tRS.%SQLCODE = 0
	{
		Do tRS.%Next()
		Set pStatus = tRS.%Get("Status")
		Set pState  = tRS.%Get("AdapterState")
		Return $$$OK
	}
	Return $$$ERROR(5001,"Status not Found")
}

Call it with the status and state variables passed by reference:

Set sc=##class(My.Class).GetConnectionStatus("T_SPM_SIU",.status,.state)

The class Ens.MessageHeader has a classmethod Purge() that deletes message headers and bodies based on the number of days to keep along with a few other criteria; those are used in an SQL query to select the set of messages to purge. That query along with the associated purge code should work as an example to see what's involved in carefully removing messages without collateral damage ... search table indices need to be maintained, for example.

There's also the Ens.Util.MessagePurge task definition that is used for scheduled purges, it has much of the same code but offers a multi-threaded purge feature that leverages the work queue.

@Enrico.Parisi's solution moves the actual purge of the messages off to the scheduled Ens.Util.MessagePurge task for messages that exceed the DaysToKeep limit, as long as that is configured to delete bodies too. This is likely the safer solution and requires significantly less effort 😉