Deploy to the cloud with a function call

Access scalable storage like in-memory data structures.

Call services as easily as local functions.

●●●
UCM
.> project.create-empty

  πŸŽ‰ I've created the project with the randomly-chosen name
  energetic-cheetah (use `project.rename <new-name>` to change it).

energetic-cheetah/main> pull @unison/cloud-start/releases/latest 

  Downloading... DONE βœ…

energetic-cheetah/main> run helloWorld.deployannotation arrowfull code example below 

  Uploading service... DONE βœ…
  
  Service deployed at:

    https://unison-services.cloud/h/nndat36oh3usll24flj6qlfpb8uk1plf20na9e1er67uo9idme60/
    https://myusername.unison-services.cloud/s/hello-world/

  View logs at: https://app.unison.cloud

energetic-cheetah/main> quit

$ curl https://myusername.unison-services.cloud/s/hello-world/Cloud
πŸ‘‹ Hello, Cloud!
.>

Features

We've packed Unison Cloud full of goodies.

Deploy web services in seconds

Describe HTTP and WebSocket deployments with a single function call. No building containers, managing VMs, or other cloud infra management. Spend your time writing service logic, not fixing YAML.

●●●
~/scratch.u
helloWorld.logic : HttpRequest ->{Exception, Log} HttpResponse
helloWorld.logic = Route.run do
  name = route GET Parser.text
  info "request for greeting" [("name", name)]
  ok.text ("πŸ‘‹ hello " ++ name ++ "\n")

helloWorld.deploy : '{IO, Exception} ()
helloWorld.deploy = Cloud.main do
  name = ServiceName.named "hello-world"
  serviceHash = deployHttp !Environment.default helloWorld.logic
  ServiceName.assign name serviceHash


Microservices, without the overhead

Make inter-service calls with a single line of code, without serialization or networking boilerplate. Get the benefits of a microservice architecture without the headache.

Reduce deployment risks with programmatic rollbacks

All service deployments are immutable and get a unique content-addressed hash. Named services have a stable URL and can point to any service version. Easily promote a deployment to production or rollback to an earlier version.

●●●
app.unison.cloud
#8LwIdQx1 A @alice 3 days ago
#G8VcMPGs Active Deploy C @carol 5 days ago
#AqjDPCC2 B @bob 6 days ago
#sS34CCmo L @logan 8 days ago
#45cKdmzL F @finley 13 days ago
#0fks3dLD T @taylor 29 days ago
#7f43dLDs L @logan 1 month ago
#G8VcMPGs A @alice 2 months ago

Typed and transactional data storage

Getting data into and and out of storage is usually a tedious layer of boilerplate in your application. With Unison Cloud, any value may be saved in our transactional storage layer. Your access to storage is statically typed and checked by Unison's typechecker.

●●●
~/scratch.u
counter : Database -> Table Text Nat -> HttpRequest -> HttpResponse
counter db userCounts = Route.run do
  (user, amount) = route.pair POST (s "increment" / text / nat)
  count = Storage.modifyGet db userCounts user 0 (x -> x + amount)
  ok.text (Nat.toText count ++ "\\n")

counter.deploy : '{IO, Exception} ()
counter.deploy = Cloud.main do
  db = Database.named "counter-service-db"
  env = Environment.named "counter-env"
  Database.assign db env
  h = deployHttp env (counter db (Table "counts"))
  ServiceName.assign (ServiceName.named "counter") h


Programmatic log management

Logs produced by your services or batch jobs are consolidated and easily viewable in the Unison Cloud UI. You can also stream or filter your logs with the full power of a programming language.

●●●
app.unison.cloud
14:12:09 GET /hello/Cloud
14:12:16 GET /hello/Alice
14:13:21 GET /hello/Bob
14:18:09 GET /hello/Cloud

Batch compute jobs

Run your ETLs, data aggregations, or other batch jobs on elastic cloud resources.

Secrets and config management

Upload secrets and config to our securely encrypted vault; access them easily from your services.

Painless promotion from dev to prod

Just swap a single function call and your service is running in the cloud instead of locally. We made Unison Cloud as easy to run on localhost as it is to run in production.

Anatomy of a
Unison Cloud app

How Unison Cloud apps are crafted

A simple counter service

This is the full logic and deployment code of an HTTP app with endpoints to increment and decrement a value in Cloud storage.

The service consists of just two definitions, one describing the routes and another for the deployment.

Service logic

Below is a simple counter service with two endpoints and a minimal persistence layer.

counter : Cell Nat -> HttpRequest ->{Exception, Remote, Log} HttpResponse
The counter function signature; indicating the type of the arguments and the return type. Cell is a Cloud storage type that we'll use to store the counter value.
counter cell =
Why is there only 1 argument when the signature says there should be 2? Because counter is returning a function from HttpRequest to HttpResponse, the representation of an http service.
  incr = do
incr is a function within the counter function. The do denotes that the function returns a delayed computation a.k.a. a thunk.
    by = route GET (s "increment" / nat)
Using the @unison/routes library we're parsing and capturing the last portion of the URL as a number. When the counter service is hit with a GET request like /increment/42, we grab the 42 portion from the URL and parse it as a Nat (natural number).
    count = Cell.modifyGet cell (x -> x + by)
Update the database Cell by incrementing the number already stored there.
    Log.info "increment" [("by", Nat.toText by), ("new-count", Nat.toText count)]
Log the counter data using the info log level
    respond.ok.text (Nat.toText count)
    
Return an HTTP response with status code 200 OK, and the count converted to text.
  decr = do
    by = route GET (s "decrement" / nat)
    count = Cell.modifyGet cell (x -> x - by)
    Log.info "decrement" [("by", Nat.toText by), ("new-count", Nat.toText count)]
    respond.ok.text (Nat.toText count)
  
The mirror of the incr function, where we decrement the number stored in the Cell by the number passed to the route.
  Route.run (incr <|> decr)
Finally, Route.run transforms our route descriptions in incr and decr into an HTTP service. The <|> tells the Routes library to try to match URLs with these routes in that order; first incr, secondly decr. If none of them match, the service will return a 404 response.
πŸ’‘ Hover over lines with indicators for detailed explanations

Deployment

Unison Cloud service deployments are described in regular Unison code.
Below is the function which exposes the counter service.

counter.deploy : '{IO, Exception} URI
The deploy function returns a delayed computation (indicated by the ' symbol in the signature). It makes use of these abilities: {IO, Exception}. Functions with this signature are runnable in the ucm with the run command.
counter.deploy = Cloud.main do
Inside Cloud.main you'll set up the dependencies and Cloud infrastructure that the service requires to run. Dependencies like the creation of a Cell table are expressed in terms of the Cloud ability.
  db = Database.named "counter-service-db"
  env = Environment.named "counter-env"
  Database.assign db env
Set up a Database and Environment by name. If a database or environment with the given names already exists (within the same Unison Cloud account), those databases and environments will be returned. Finally we're assigning Database to the Environment.
  count = Cell.named db "count" 0
    
A Cell represents a single value stored in a Database. Here we're creating a Cell named "count" and fill it with the number 0. We pass this Cell to our service a bit further down.
  serviceHash = Cloud.deployHttp env (counter count)
Here's where the deployment of our counter service (defined above) happens. Once deployed, a ServiceHash is returned. The hash is created from the code being deployed; it uniquely identifies the service deployment.
  ServiceName.assign (ServiceName.named "counter-service") serviceHash
Finally, we're assigning the ServiceHash to a ServiceName, returning the URL of the service.
πŸ’‘ Hover over lines with indicators for detailed explanations

πŸŽ‰ Ta-da! That's the whole example.
Browse the codebase and docs in the @unison/cloud-start project.

Β© 2024 Unison Computing , a public benefit corp Β· Terms of Service Β· Privacy Policy Β·