WOLFRAM

Introducing Wolfram Application Server

Wolfram Application Server is a new platform developed by Wolfram Research enabling customers to deploy Wolfram Language–powered APIs and webpages into a scalable, highly available enterprise cluster.

Wolfram Application Server lets you:

We have designed Wolfram Application Server for customers who for regulatory, security or business reasons may not wish to deploy onto the Wolfram Cloud but prefer to host their Wolfram Language applications on clusters they control.

Introducing Wolfram Application Server

Wolfram Application Server tightly focuses on stateless web applications built around functions like APIFunction, FormFunction and HTTPResponse, eschewing online notebook interactivity and user session management. (If those features are important to you, then consider Wolfram Enterprise Private Cloud.) Wolfram Application Server components are built into containers (Docker) and integrated with Kubernetes, the most popular container management system, to yield maximal flexibility for deploying into your cluster, using either your own hardware or a third-party cloud provider. This makes Wolfram Application Server an ideal platform for deploying enterprise-grade applications built with the Wolfram Language and Wolfram technologies.

How It Works

Wolfram Application Server is built around microservices that make it easy to deploy and host Wolfram Language–based applications. The Active Web Elements Server (AWES) service is responsible for handling end-user requests. Each AWES instance manages a pool of Wolfram Engines that handles the computations your Wolfram Language APIs need. The AWES uses the same technologies to deliver Wolfram Language content that powers sites like Wolfram|Alpha. Your Kubernetes cluster can be configured to dynamically manage instances of the AWES to meet user load and ensure constant availability of your applications.

To support transparent deployment of applications to Wolfram Application Server, a pair of additional services are provided: the Resource Manager and the Endpoint Manager. Any content to be accessed by an end user is deployed as a resource through the Resource Manager. The Resource Manager stores the uploaded content in persistent storage and updates any AWES instances with information about the resource, which can be fetched as needed in response to user requests.

Resources themselves, however, are not directly accessible to end users. To make a resource publicly available, an endpoint must be created to map a public path to the internal path of the resource.

The Endpoint Manager creates, modifies and deletes endpoints. By decoupling the resource from the user endpoint, Wolfram Application Server developers gain additional flexibility in presenting content to users. For example, using endpoints makes it easy to maintain and switch between versions of an application for A/B testing or to quickly undo an update if a bug should appear.

Wolfram Application Server also offers a service to deploy files directly to the local file system of all the servers in the cluster: the Node Files Manager. Typically, these node files are configuration files and packages for the Wolfram Engine to support deployed resources. The Wolfram Engine accesses the local file system to read these types of files, so they must exist there, unlike resource files that may or may not be cached locally. Other types of files typically distributed as node files can include compiled executables and libraries that may be called or loaded by the Wolfram Engine. Node files are not end-user accessible and cannot be referred to by an endpoint. They are intended for internal use only by the Wolfram Engine.

Finally, a pair of supporting services are provided and used by Wolfram Application Server but not directly accessed by public APIs. The Storage Service and the Streaming Service provide necessary support for applications behind the scenes.

The Storage Service provides persistence and a single source of truth (SSOT) for all deployed resources. For clusters built in the cloud, the storage will be either Amazon’s or Microsoft’s native object storage. For clusters built from your own hardware, an additional application is provided.

The Streaming Service enables communications between the various instances of services in the cluster and is necessary for keeping existing instances in sync with the state of the cluster (e.g. existing resources and endpoints) and for provisioning new instances when they come up (e.g. when a new AWES is added to handle excess load).

An Example Deployment

All of the services discussed in the previous section are accessible through documented representational state transfer (REST) APIs, but we can also access these services through the Wolfram Language. We have built a full set of tools packed in the Wolfram Application Server paclet for managing deployments through our service framework. Install the paclet by evaluating:

Engage with the code in this post by downloading the Wolfram Notebook
PacletInstall["WolframApplicationServer"]
&#10005

PacletInstall["WolframApplicationServer"]

Then load the Wolfram Application Server package:

Get["WolframApplicationServer`"]
&#10005

Get["WolframApplicationServer`"]

Now we can connect to a Wolfram Application Server cluster:

was = ServiceConnect["WolframApplicationServer", "https://test.applicationserver.wolfram.com"]
&#10005

was = ServiceConnect["WolframApplicationServer", 
  "https://test.applicationserver.wolfram.com"]

Creating a deployment is a simple matter of using ServiceDeploy to deploy the resource and generate the endpoint. Note that we use the "Contents" entry to provide the Wolfram Language with what we want evaluated (in this case an APIFunction); the "Resource" entry to give a path to the resource, which is for internal use; and the "Endpoint" entry to give the public path to the resource:

deployment = ServiceDeploy[ was, <|"Contents" -> APIFunction[{"name"}, StringJoin[{"Hello ", #name, "!"}] &], "Resource" -> "example/hello.wl", "Endpoint" -> "example/hello"|>]
&#10005

deployment = 
 ServiceDeploy[
  was, <|"Contents" -> 
    APIFunction[{"name"}, StringJoin[{"Hello ", #name, "!"}] &], 
   "Resource" -> "example/hello.wl", "Endpoint" -> "example/hello"|>]

Here is the full information about the deployment we just created:

Information[deployment]
&#10005

Information[deployment]

We can now access the deployed web application:

URLRead[URL[ "https://test.applicationserver.wolfram.com/example/hello?name=world"], {"StatusCode", "Body"}]
&#10005

URLRead[URL[
  "https://test.applicationserver.wolfram.com/example/hello?name=world"], {"StatusCode", "Body"}]

We can inspect and manipulate the parts of a deployment using the more detailed API provided by the Wolfram Application Server service. For example, we can get back the contents of the deployed resource:

was["ResourceContents", <|"Resource" -> "example/hello.wl"|>]
&#10005

was["ResourceContents", <|"Resource" -> "example/hello.wl"|>]

If we would like our resource to be accessible from an alternate path, we can deploy a second endpoint that points to the same resource:

was["DeployEndpoint", <|"Endpoint" -> "example/hi", "Resource" -> "example/hello.wl"|>]

&#10005

was["DeployEndpoint", <|"Endpoint" -> "example/hi", 
  "Resource" -> "example/hello.wl"|>]
URLRead[URL[ "https://test.applicationserver.wolfram.com/example/hi?name=world"], {"StatusCode", "Body"}]
&#10005

URLRead[URL[
  "https://test.applicationserver.wolfram.com/example/hi?name=world"], \
{"StatusCode", "Body"}]

We might prefer this version to be a little more informal. We can deploy a new resource for that:

was["DeployResource", <|"Resource" -> "example/hi.wl", "Contents" -> APIFunction[{"name"}, StringJoin[{"Hi ", #name, "!"}] &]|>]
&#10005

was["DeployResource", <|"Resource" -> "example/hi.wl", 
  "Contents" -> 
   APIFunction[{"name"}, StringJoin[{"Hi ", #name, "!"}] &]|>]

Then update the endpoint:

was["DeployEndpoint", <|"Endpoint" -> "example/hi", "Resource" -> "example/hi.wl"|>]
&#10005

was["DeployEndpoint", <|"Endpoint" -> "example/hi", 
  "Resource" -> "example/hi.wl"|>]

Now we try that again:

URLRead[URL[ "https://test.applicationserver.wolfram.com/example/hi?name=world"], {"StatusCode", "Body"}]
&#10005

URLRead[URL[
  "https://test.applicationserver.wolfram.com/example/hi?name=world"], \
{"StatusCode", "Body"}]

Of course, we are just scratching the surface of all that you can do with Wolfram Application Server, but I hope that you can see how easy it is to deploy content and start building powerful applications. Finally, before we go, we will be polite and clean up what we have created:

was["DeleteEndpoint", <|"Endpoint" -> "example/hello"|>]; was["DeleteEndpoint", <|"Endpoint" -> "example/hi"|>]; was["DeleteResource", <|"Resource" -> "example/hello.wl"|>]; was["DeleteResource", <|"Resource" -> "example/hi.wl"|>]

&#10005

was["DeleteEndpoint", <|"Endpoint" -> "example/hello"|>];
was["DeleteEndpoint", <|"Endpoint" -> "example/hi"|>];
was["DeleteResource", <|"Resource" -> "example/hello.wl"|>];
was["DeleteResource", <|"Resource" -> "example/hi.wl"|>]
Contact your sales representative to learn more about Wolfram Application Server.

Comments

Join the discussion

!Please enter your comment (at least 5 characters).

!Please enter your name.

!Please enter a valid email address.