Develop Lambdas with any programming language

I just wanted to give a quick update.
I’ve successfully setup an environment, that supports WASM for Lambda in Go, Rust and AssemblyScript. Currently I’m mainly testing in Go and unfortunately there is some (generated) boilerplate code needed to make using resolvers pleasent (Generate Go Types, JSON marshaller/unmarshaller, wrappers that allow sending strings (JSON) between host and guest.
I was new to WASM and a limitation is the fact, that you cannot just send all types of data back and forth, for example strings. That requires some memory management. I will show this off soon to gather feedback.

Now onto a question I have:
In accordance to this “feature request”, we defined it would be ideal to support both local lambdas as well as (multiple) external. Therefore my suggestion would be:

  • Add @lambda([url: “…”]) with optional url as mentioned in here.
    @lambda without url runs on local server. @lambda with url is sent to external lambda.
  • Remove the lambda superflag.
    url is implicit from schema - can be removed.
    num is defined through admin api and defaults to 1.
    port is defined through admin api and defaults to 6868.
    restart-after is defined through admin api and defaults to 30s
  • Startup local lambdas when the schema is being loaded and a @lambda directive without url is detected.
  • Send requests to external lambdas dynamically (no prior definition in superflag needed).

What’s your feedback? Am I missing something?
Thanks.

1 Like

I threw away all of my experience deploying Dgraph/Lambda long ago. But I believe this is the logical conclusion of the matter.

1 Like

Thanks for the feedback. I have another question now.
The alpha currently starts the lambda servers in separate processes. The reason behind this is probably, that the alpha servers are running in a Node environment.
As my implementation runs within Go, we could integrate the lambda more closely within DGraph alpha.
What do you think about that? What risks could that impose?

Options:

  • Run lambda/wasm instances as goroutines within dgraph alpha.
    Advantage: Highest performance gain I would guess. No HTTP/GRPC transmission needed. Direct embedding of wasm runtime within alpha.
    Disadvantage: Might not be separated enough, although I think separation through WASM modules is enough. Potential security risks?

  • Run lambda/wasm instances as goroutines within one external process.
    Advantage: Separation of lambda and alpha - Less impact on malfunction and in terms of security risks.
    Disadvantage: Minimal performance losses due to transmission. Process management.

  • Run lambda/wasm instances as goroutines within multiple external processes.
    This should not be necessary as go automatically uses multiple cores.

I hope I delivered the question understandably. I personally would think about integrating the lambda directly into alpha and run wasm instances within goroutines.

Thanks in advance.

I don’t know much about golang environments. I know that a crash in the lambda script needs to be handled so it doesn’t crash the alpha however that works

1 Like

If you are using a pool of executors (configurable semephore) for executing ‘natively’ that sounds ideal to me. Definitely need to test fault in WASM as to not effect the alpha process but I assume the WASM engine handles that already. Does the WASM engine allow resource sandboxing too? Like max X memory? (appears so)

exec’ing nodejs is what felt terrible to me, so I would say not that model.

1 Like

I would go with option 1 (embedding lambda within alpha) as it is the easiest to maintain / most performant option, however I would use golang plugin infrastructure, so the lambda logic would be loaded only if/when a schema with @lambda is loaded in (see Writing Modular Go Programs with Plugins | by Vladimir Vivien | Learning the Go Programming Language | Medium) , so when you do not need lambda functionality, you avoid loading (potentially big) unnecessary code.
Then you can have different implementation within the plugin (pool of goroutines, launching external process, using remote services etc).
If I was to write an embedded lambda server for alpha (and I might one day), I would like to use a plugin with goper-lua engine (GitHub - yuin/gopher-lua: GopherLua: VM and compiler for Lua in Go) and lua scripts. Then I could use the same “entry points” (golang plugin with defined interface).

The go plugin ergonomics are terrible, having to have exactly the same hash of every dep and compiler as the server is terrible unless you are compiling at the same time. This is my experience with the custom tokenizers in Dgraph which already use go plugins.

But WASM allows everything you said: loading on demand, etc. And then you would not have to worry about syncing dependencies and could write it in any language you want, including lua (embedded in go,rust, or cxx)

OK, have no experience with WASM, looking forward to test it. Thanks for the info.

If you are using a pool of executors (configurable semephore) for executing ‘natively’ that sounds ideal to me.

I’ve come to the conclusion that incoming requests should be concurrent anyways. Therefore it would be better to make the lambda thread safe and there would be no need for starting up goroutines and a limitation is not really needed. I’m creating a wasm instance for each namespace that has a lambda script stored now. This means I don’t have to check the schema.

however I would use golang plugin infrastructure

I honestly don’t remember any specifics anymore, but I also tried the golang plugin stuff in the past and it was a very unpleasant experience.
For now I’m implementing the lambda with wasm.

No matter the solution I’ve come up with another constraint - backwards compatibility.

  • We should support Node for at least one more version to allow devs to switch technology. Or should Node support be kept indefinitely?
  • DGraph Cloud allows to write resolvers within the UI. This would not really be possible with wasm as it needs to be compiled. Alternatively a simple upload button could be provided. This would also speak for keeping Node in addition to wasm.

How critical are such things seen by the core-dev team? How important is backward compatibility? Should we support both wasm and node? Who should I ask?

Can you execute the JavaScript lambdas in WASM? I feel like that should be a thing since anything could compile to WASM. But yea, JavaScript should continue to be supported for continuity I imagine.

Yes using AssemblyScript you can create a wasm from Typescript/JavaScript. So there is a possibility for devs to migrate, but some changes are needed. Compilation of scripts written in DGraph Cloud UI could be handled by the server using also AssemblyScript.

Thanks again for the feedback. Gonna work on supporting both.

I’m just coming into this and have a substantial vested interest in golang lambdas.

I was able to get main branch of GitHub - Schartey/dgraph-lambda-go working for very simple lambda resolvers, but largely exit 1 for most invocation of generate on schema.graphql

I would love to get involved.

If I am planning to invest substantial time here should I start digging into wasmer-go with next branch?
Based on this thread I’m assuming the next refactor with is mainline now, and existing main implementation will be deprecated. For now I will focus on next.

Cheers
Thank you for spearheading @Schartey