Written by

Senior Iris developer
Question Nicki Vallentgoed · Nov 8, 2024

External language server IRIS to IRIS?

Intersystems provides External language server connections for various languages which,
from a development perspective, is great as I can keep my application code separate but still interact with the IRIS kernel.

It becomes more complex though if you are using Interoperability etc where you might end up with some code in IRIS and some code in another language.
What would be great is having an IRIS to IRIS language server where the application code and stay IRIS based but separate from the database?

Product version: IRIS 2024.1

Comments

Timo Lindenschmid · Nov 8, 2024

The beauty of the IRIS technology stack is that code and data is withing the same instance.

To separate code from data ISC uses the idea of code and data databases, which can be configured on a namespace level, this combined with global, package and routine mappings results in very versatile environment that should satisfy every need. If you want to actually separate compute from data storage, this is also possiple using the ECP protocol with dedicated app servers. 

0
Nicki Vallentgoed  Nov 8, 2024 to Timo Lindenschmid

Fair point but I do find it odd.
Using e.g the Native SDK for Python I can have multiple applications on different servers all communicate directly with the IRIS kernel.
But I cannot do the same with IRIS to IRIS.
There are some benefits:
No added complexity.
Easy separation of applications.
Easier development management.
Easier deployment of application updates.
 

0
Eduard Lebedyuk · Nov 8, 2024

Here's how to do it (sample code to transfer files over iris connection):

/// Get IRIS connection object/// set iris = ##class().GetIRIS()ClassMethod GetIRIS() As%Net.DB.Iris
{
    Set host = "host"Set port = 1972Set ns = "%SYS"Set user = "_SYSTEM"Set pass = "***"Set connection = ##class(%Net.DB.DataSource).CreateConnection(host, port, ns, user, pass)
    Set iris = connection.CreateIris()
    Quit iris
}

/// Transfer one file from sourceFile to targetFile on iris connection.ClassMethod Transfer(iris As%Net.DB.Iris, sourceFile As%String, targetFile As%String) As%Status
{
    Set sc = $$$OKTry {
        Set stream = ##class(%Stream.FileBinary).%New()
        Do stream.LinkToFile(sourceFile)
        Set var = "%stream"Do iris.ClassMethodVoid($classname(), "InitStream", var, targetFile)
        While 'stream.AtEnd {
            Set chunk = stream.Read($$$MaxStringLength-1000)
            Do iris.ClassMethodVoid($classname(), "WriteStream", var, chunk)
        }
        Do iris.ClassMethodVoid($classname(), "SaveStream", var, ##class(%File).Attributes(sourceFile))
    }
    Catch ex{
        Do##class(%SYS.System).WriteToConsoleLog("SuperServer Copy failure in Transfer:" _ ex.DisplayString())
        Throw ex

    }

    Quit sc
}

/// Initialize stream for subsequent write requests and place it in var./// var must be a global variable (start form %) /// file is created or truncated if already existsClassMethod InitStream(var As%String, file As%String)
{
    Try {
        Do##class(%File).Truncate(file)
        Set stream = ##class(%Stream.FileBinary).%New()
        Do stream.LinkToFile(file)
        Set @var = stream
    } Catch ex{
        Do##class(%SYS.System).WriteToConsoleLog("SuperServer Copy failure in InitStream: " _ ex.DisplayString())
        Throw ex
    }
}

/// Wrile string into a stream initialized by InitStream ClassMethod WriteStream(var As%String, string As%String)
{
    Try {
        Do$method(@var, "Write", string)
    } Catch ex{
        Do##class(%SYS.System).WriteToConsoleLog("SuperServer Copy failure in WriteStream: " _ ex.DisplayString())
        Throw ex
    }
}

/// Save stream initialized by InitStream. /// Optionally sets file attributes.ClassMethod SaveStream(var As%String, attributes As%String = "")
{
    Try {
        Set sc = $method(@var, "%Save")
        Set file = $property(@var, "Id")
        Kill @var
        Do:attributes'=""##class(%File).SetAttributes(file, attributes)
    } catch ex {
        Do##class(%SYS.System).WriteToConsoleLog("SuperServer Copy failure in Savetream: " _ ex.DisplayString())
        Throw ex
    }
}

Use ClassMethodValue to get a scalar value back. Use json for complex type transfer as objects are not supported. There are other methods corresponding to APIs in other languages.

Also please note that this class (technically only the callee *Stream methods but save yourself a headache and just copy the entire class) needs to be present on both nodes.

Finally, remember that callee methods must produce no stdout/stderr writes, since the io is bound to the iris connection itself and it cannot disambiguate stdout.

0
Nicki Vallentgoed  Nov 11, 2024 to Eduard Lebedyuk

Thank you very much.
Quick question about the port.
Is it the standard port the IRIS instance is running on?
I do not need an external language server connection on the host?

0
Eduard Lebedyuk  Nov 11, 2024 to Nicki Vallentgoed

Quick question about the port. Is it the standard port the IRIS instance is running on?

Yes, 1972 is a default Super Server port.

I do not need an external language server connection on the host?

External language servers talk to Super Server, so in a case of IRIS to IRIS we can just talk to Super Server directly.

0