acb's technical journal

Posts matching tags 'futures'

2016/2/11

Malimbe: an asynchronous server-side web framework in Swift

Recently, I have been experimenting with the open-source beta of Swift for Linux, and in particular looking into its potential as a language for server-side web applications. As such, I present the first draft of my experimental server-side web framework, Malimbe.

Malimbe (named after several species of African weaver bird) is written in Swift and will build on Linux; no attempt has yet been made to make it work on OSX, though it would certainly be possible. The main influences on Malimbe's design have been various Python/WSGI-based frameworks (mainly Pylons/Pyramid) and the Play framework in Scala (though Malimbe is a lot more minimal at this stage). The key design decisions of Malimbe, as it currently stands, are:

  • The use of Futures (as previously described here) for concurrency. HTTP request handlers do not return a HTTPResponse immediately, but return a Future<HTTPResponse>; i.e., an opaque container to a computation, which, once complete, will yield a HTTPResponse. The Future may refer to an ongoing computation, taking place on a background thread, or (for simple responses) may be created pre-completed. Given that Futures are monadic containers (which may be mapped and flatMapped over), a request handler returning a Future<HTTPRequest> could well just call a function returning a Future of, say, a set of database rows or a JSON object fetched from a remote API, and return that mapped into, say, a page of HTML.
  • Malimbe's request-handling mechanism is a chain of objects implementing the HTTPRequestHandler protocol. This protocol defines only one method, which looks like:
    func handleRequest(request: HTTPRequest) -> Future<HTTPResponse>
    
    The request handler objects are typically instantiated with any configuration information they need; for most of them, this will include a next value, containing the next request handler in the chain. If the request handler cannot completely handle the request itself, it will call this and return its value. (Theoretically, it could also modify its return value with map or flatMap, though none of the ones implemented so far do.)

The main source file of a Malimbe web application, as it stands, constructs the chain of request handler, and creates a HTTPServer object (passing the top of this chain to it); requests propagate down the chain until they are handled; at the bottom is typically the Router request handler, which matches methods and paths, extracting arguments from paths, and calling the appropriate handler for each path. This might well look something like:

func itemPageHandler(request: HTTPRequest, args:[String:String]) -> Future<HTTPResponse> {
    let id = args["id"] ?? ""
    // make the item page here...
}

let router = Router(routes:[
	Router.Get("/items/",    handler:itemsListHandler),
	Router.Get("/items/:id", handler:itemPageHandler),
])

let staticFiles = StaticFileRequestHandler(pathPrefix: "/static/", staticDir:appRelativePath("StaticFiles/"), next:router)

let server = HTTPServer(handler: staticFiles)

do {
    try server.start(9999)
    print("started on 9999")

    while(true) {
        NSRunLoop.mainRunLoop().runUntilDate(NSDate.distantFuture())
    }
} catch {
    print("error: \(error)")
}

Malimbe currently has a few request handlers: the path-matching Router shown above; StaticFileRequestHandler, which can conveniently serve static files (such as stylesheets and JavaScript) from a local directory under a certain path, along with a HTTP Basic Authentication middleware; others will be added in future.

HTMLRenderable

Malimbe also has a simple set of objects for generating HTML in Swift code. This, Swiftily enough, has a protocol at its centre, the HTMLRenderable protocol, which allows objects to return HTML representations of them:

public protocol HTMLRenderable {
    /** Return a HTML representation of this object as a String */
    var asHTML: String { get }
}

The Swift String type has been extended to be HTMLRenderable; a string rendered asHTML will be quoted, with angle brackets replaced with &lt; and &gt; so that its contents are displayed as they are. If you wish to pass HTML markup back, there is a HTMLLiteral object you can wrap it in, which renders without any quoting. However, in most cases, you will want to create tags using the HTMLTag type, a HTMLRenderable representing a single tag and its contents (which may include zero or more HTMLRenderables within the tag), like so:

HTMLTag.DIV([
    HTMLTag.SPAN(HTMLTag.B(self.name), "says:", class:"itemtop"),
    HTMLTag.DIV(self.text, class:"itembody")
], class:"guestbookitem")

(The tag's contents are the first rather than last parameters; this is because of quirks in Swift's handling of variadic arguments.)

Of course, since HTMLRenderable is a protocol, there is every reason to extend your data types to implement it, which then allows you to insert them directly in the markup:

extension Item: HTMLRenderable {
    var asHTML: String {
        return HTMLTag.P(
            "Item ", HTMLTag.B(self.id), "(\(self.name))"
        , class: "item").asHTML
    }
}

The state of the framework

Malimbe is an experimental framework, still in an early stage of development. Many pieces that one would expect in a full stack are missing (notably any support for access to databases or web-based APIs). Some of these may be developed separately as other projects and imported as dependencies into Malimbe-based projects, though ideally, Malimbe would integrate them into its design. (For example, once a database framework exists, it would be the intention for it to be wrapped in an asynchronous interface that returns Futures of results.) Other components (such as session middleware, templating libraries, and a configuration system) are also missing at this stage.

Also, because Swift support on Linux is still immature, Malimbe applications will probably not be performant at this stage. For one, at the time of writing, there was no stable Linux port of libdispatch (Apple's concurrency framework, also known as Grand Central Dispatch); Malimbe uses a workaround from a Swift package named NSLinux which fakes this by spawning a thread for each dispatched block; this is obviously not something one would want on a heavily loaded production server. However, once libdispatch is ready, Malimbe will not require significant changes to use it.

Malimbe is available on GitHub, and is distributed under the Apache Licence (i.e., it may be used freely, as long as acknowledgement is provided).

futures linux malimbe swift web 1

2016/1/18

Futures/Promises in Swift, draft 1.1

With the recent open-sourcing of the Swift language and its availability (albeit piecemeal, and not quite as we know it) on Linux, I have been spending some time playing with Swift on Linux. In my opinion, it holds promise for implementing the sorts of server-side code that often runs on Linux instances; one example would be web applications. With its LLVM-based optimising compiler, strong type system and the ability to minimise the amount of mutable state (more so than, say, Python or JavaScript), it should lend itself to performant server-side code quite well.

In any case, here is the first result of my experiments in Swift on Linux: a proof of concept of Futures/Promises. It's modelled somewhat on Scala's Futures, in that Futures are monadic containers which may be transformed with map, chained with flatMap, and, should you need to go synchronous at some point, awaited.

(For those not familiar with Futures/Promises, they're a different way of organising callbacks. With callbacks, as we know them from, say, JavaScript, Objective C or Swift, if you have a possibly time-consuming process to run, you pass it a function for it to call; it returns nothing immediately, but if all goes well, your callback function gets called with the value it was waiting for. Of course, the downside of this is the building up of a “Pyramid Of Doom”, a monstrous ziggurat of curly braces, like so:

doSomething { (a) -> () in 
   doSomethingElse(a) { (b) -> () in 
     andSomethingElse(b) { (c) -> () in 
        // now handle the value here
   }
}
With Futures/Promises, you don't pass callbacks, but instead receive an opaque container type that is, at some future time, redeemable for the value of whatever computation it represents. While you don't have that value, you can do other things with it, like chain other operations on it, to be completed asynchronously. And so, our pyramid is transformed into something like;
doSomething()
  .flatMap { doSomethingElse($0) }
  .flatMap { andSomethingElse($0) }
  .onCompletion {
    // now handle the value here
  }
Which, for one, looks a bit tidier; it also allows complex chains of interdependent operations to be reasoned about more easily.)

This code is currently only a rough sketch (which is why it is a gist, rather than a repository); for one, Swift on Linux's concurrency handling still leaves a bit to be desired (Apple's libdispatch is still not available, and so this uses NSLinux, which fakes Grand Central Dispatch in a somewhat basic way, spawning a new thread for each block, and having no option of running things on the main thread; needless to say, don't use this in your financial trading app just yet.) Secondly, there is not yet a concept of a failed Promise; they may be either incomplete or successfully completed. (Whether to use a Haskell-style Either/Result value or to somehow eschew that in favour of Swift's throws mechanism is a decision to be considered when implementing the possibility of failed Promises. Also, some way of sequencing/traversing multiple Futures would be useful for nontrivial applications. Finally, there is the small matter that this code defines only a Promise type and has it do double-duty as a Future as well; which makes for simpler code, though doesn't separate the twin concerns quite as elegantly. Update: I have now updated the code to split Futures (the ones you fire off with a block to run in the background) from Promises (the ones you create and fill in yourself, giving a Future to whatever needs the result).

In any case, the typical usage would look something like the following:

// Map over a Future, then do something with its result asynchronously
var f1 = Future<Int>( future: { calculateValue(...) })
var f2 = f1.map { $0 * 2 }
f2.onComplete { doSomethingWith($0) }

// two futures chained with flatMap
var f3 = Future<String>( future: { getUserName() })
    .flatMap { Future<Int>( future: { getShoeSizeOfUser($0) } }
if let value = f3.await(3.0) {
    print("The user's shoe size is \(value)")
}

And if you want to use Promises and do the computation yourself:

func asynchronouslyComputeAFuture() -> Future<Something> {
    // create an empty Promise...
    let p = Promise<Something>()

    // start a background process which will fill the Promise in...
    dispatch_async( myQueue, {
        let result: Something = computeTheResult() // this may take a while...
        p.complete(result)
    })

    // return the Promise's Future
    return p.future()
}

This is not the only implementation of Futures/Promises for Swift, nor even one of the more complete ones. There are two others which look more complete (BrightFutures and FutureKit), though both are only available for iOS and OSX at the moment.

concurrency functional programming futures linux monads promises swift 1

This will be the comment popup.
Post a reply
Display name:

Your comment:


Please enter the text in the image above here: