About this video
What You'll Learn
- Compare Spin's Nomad-backed runtime to Kubernetes and Krustlet for WebAssembly workloads
- Build a Rust HTTP microservice that uses Prisma with CockroachDB
- Run the compiled Wasm app locally, inspect routes, and deploy to Fermyon Cloud
David explores Fermyon's Spin, comparing its Nomad-based runtime to Kubernetes via Krustlet, then builds a Rust HTTP microservice backed by Prisma and CockroachDB, running it locally before deploying to Fermyon Cloud.
Jump to a chapter
- 2:42 Introduction and Overview
- 3:33 Spin's Architecture and Kubernetes Comparison
- 9:02 Language Support and WebAssembly Ecosystem
- 12:28 Understanding Spin Concepts and Structure
- 21:04 Q&A: Spin App Design Strategy
- 21:53 Setting up the Demo: Database with Prisma
- 31:10 Exploring the Application Code (Rust)
- 38:50 Building and Running Spin Locally
- 42:51 Local Debugging and Dynamic Route Test
- 44:01 Deployment to Fermion Cloud
- 46:51 Final Q&A and Conclusion
Full transcript
Generated from the English captions. Timestamps jump the player to that moment.
Read the full transcript
2:42 Introduction and Overview
2:42 Hello, and welcome back to the Rawkode Academy. My name is Dylan Flanagan. Although you may know me from across the Internet as Rawkode. Today is a solo hands on expedition as I explore a product called Spin from a company called Fermion. Full disclosure, I have been doing some work for Fermion recently, helping them produce content to show the world how cool WebAssembly could be. And we're gonna run through a few of those examples that I've been working on today, as well as cover the basics about what Spin is, what Fermion are trying to achieve, and of course,
3:15 writing some code. Well, you know, I mean, we rely on Copilot to do most of the heavy lifting. So if you wanna keep me company, feel free to say hello in the comment section. Let me know if you have any questions about Fermion, Spin, or WebAssembly as we run through today's exercises. What I will do is since I'm wearing a custard Kubernetes t shirt and the first kind of question came in during the holding screen. Let's tackle that. So Russell says that he is interested to hear what I think about Spin as he's heard it is designed
3:33 Spin's Architecture and Kubernetes Comparison
3:51 for Nomads rather than Kubernetes. So I don't have a link prepared now, but the first piece of content I did with Fermion was an interview with the two co founders. So that's Rado, the CTO, and Matt, the CEO. They're both responsible for or at least they were contributors and maybe even creators. I can't remember the exact specifics. Think they were the creators and the maintainers and the contributors of a pro project called Crustlet, which was a fake kubelet to allow you to run WebAssembly workloads in Kubernetes. This is a project I've actually covered multiple times, maybe not on this channel directly, but
4:34 there may have been an episode or a hack, but I have definitely played with it and talked about it when I were to Equinix and on my Discord channel once or twice. So running WebAssembly to me has always been interesting and doing it in Kubernetes means that I can transfer a lot of that knowledge and experience that I already have. And, of course, I can run workloads side by side. Like, there's no reason I can't run container based workloads next to web assembly workloads, next to virtual machine workloads. And Kubernetes does give us a control
5:02 plane that is extensible enough to allow us to do that. Looking back to what I said about the first piece of content I did to Fairbeam was an interview with the two founders as that one of the things that they shared was that they really pushed Trustlet, and it took a lot of effort to get a system that kinda worked. But what they found is they weren't really getting the characteristics that they expected from pushing that, you know, an alternative runtime into Kubernetes that doesn't really conform to the CRI spec. The container resource interface spec is is there
5:36 to run containers. You can run other things, but Kubernetes and, you know, the and the CRI make a lot of assumptions about there always being a process within namespaces. And WebAssembly doesn't work that way. It's got its own sandbox, which is provided by WasmTime or Node. Js isolates or whatever that runtime is gonna be. So it doesn't even have any concept of of POSIX. Now while there's work with the Wazi specification, it's gonna bring that to WebAssembly, at least server side WebAssembly. These are things that are being added through something called the capability model, which allows you to extend
6:17 the WebAssembly sandbox with new features by providing the ability to either gRPC or HTTP call out to alternative systems, which have again more constraints in place. So what they said in there, and I will send the link to this interview. I'll stick it into the show notes. You just go to youtube.com and search for Fermion, it's on their official channel. It was the most recent video I believe. It's a really interesting interview, but I keep it off topic. But the the thing that really trying to drive home about why they went with Nomad rather than continuing, you know,
6:51 they've got a lot of experience in Kubernetes too. These are people that work on the Azure cloud team pushing Kubernetes. They are responsible for Helm. They're responsible for Brigade. They're responsible for Crustlet. Kubernetes was their bread and butter. However, what they said was they pushed it as far as they could get it. And the startup times for containers are slow. If you need to run a new container, you're talking hundreds of milliseconds, potentially seconds depending on whether, you know, network image is there, IP address space, a whole bunch of other things. Things they don't really need to worry about
7:25 with WebAssembly. And one of the things that they kind of affirmed in our interview was that Nomad is built to run different types of workloads. It runs containers, but it can also run the JVM. And, actually, the JVM is much more compatible as a runtime to WebAssembly than it is to containers. So what they what they said in this I'm just gonna kinda reveal the whole interview now instead of making you go watch it. But what they shared there is that with Nomad, they have the ability to schedule new workloads and have almost sub millisecond
8:00 initialization, bootstrap, and start of web assembly workloads on Nomad. Something that just wasn't possible on Kubernetes. A strong proportion of our interview, Matt and Raghu focus on WebAssembly is not a all end situation. You know, while we may have a future where entire companies and applications are built on WebAssembly, they really see them as complementary technologies. Like, you will always need containers. You will still need VMs. We still need VMs today even though we have containers. So web assembly is there to enrich and augment those container based and virtual machine based or or even bare metal workloads if that's how
8:39 you're operating. But give us a development experience that works locally and remotely just the same. And that's really what I wanna show today is I play with Spin and explore it. So that was that a bit of a divergence just to answer that first question, but I hope that context, the history, that flavor is useful to you. Russell, if you have any more questions drop them straight into the chat. I see we have a question from Moz as well. So thank you for joining us, Moz too. The first time I saw WebAssembly when I was trying to learn how to write on
9:02 Language Support and WebAssembly Ecosystem
9:12 voice filters using TinyGo. That's the Spin project use TinyGo or something else. Excuse me. Okay. So spin allows you to write and develop micro services in almost any language. And we'll cover a few of the constraints there today. If you write your spin application using their Go SDK, it does use tiny go. Yes. It also supports rust out of the box and for that you're just using standard rust with, you know, was a target. And yeah, really rust makes it really really easy. Put on to I go block someone in the comment. It's not quite made it onto live yet.
10:02 I could just see here. I don't have the ability to block from here. Oh, they've built I think YouTube got them. Alright. Thank you YouTube automation. So, yeah. It uses technical Rust just uses Rust and then any language that really compels them to web assembly can be used. You won't have access to the same abstractions provided by Spin, but you can still do a lot of things. What I really loved about Spin is that different modules can be written in different languages, you can still just consume them because once you've produced that artifact that target that small
10:34 wasm dot file, you just ship it to OCI or somewhere else that can be consumed. And I don't know if you're familiar, but Docker desktop made a big announcement two weeks ago. That would be the November for anyone not watching his life where they said that actually now you can use Docker pull commands to pull down WebAssembly boundaries from OCI registries. And Docker Hub now supports OCI artifacts. So all these things are coming together. And then the special sauce from Docker is actually you can run containers and WebAssembly side by side. So I missed this in an announcement,
11:08 but someone pointed out to me just earlier in the week. But you can write a Docker Compose file that runs a bunch of containers as you always have. However, now one of those services could be a Wasm binary, And it just runs side by side, does the thing, and communicate with the other services. And I think that's pretty special. And I I really I'm really excited now. And I I mean, I've always been excited about WebAssembly. If you're in my Discord server, you'll you'll see many chats about WebAssembly and the things that we want to do with it, like
11:36 a trial project and other things. But really interesting being able to have a Docker Compose file that we know we're comfortable with, we've used before, we've been using for years and just stick a WebAssembly service into there. And that's something I definitely will be exploring more on the channel and they come in days, weeks, or months. So, Mozz, yes. A lot of way of saying tiny go is what it uses there. Russell's saying thank you for the answer. My pleasure. And then Russell is saying, I wonder if they will tell me team up with Nova.
12:10 Yeah. That project is really cool. I'm not sure. I've never said it out loud before, but definitely, you know, we're we're gonna see more innovation in this space with cohesive multi runtime component things happening side by side. And I think that's really interesting. So let's let's get started. I don't expect to do ten to fifteen minutes of questions, but really, really interesting ones. So thank you both for answering asking. I had fun answering. And if anyone has anything else, drop it straight into the comments. I always love to kinda sit and talk. What I'm gonna do now
12:28 Understanding Spin Concepts and Structure
12:49 is share my screen. And I'm gonna pull down our website as well while I'm at it. There we go. So this is the the fermion website at fermion.com. We're gonna be taking a look at Spin today, which is their web assembly framework. It allows you to build web assembly applications and provides all the craft, the boilerplate, the glue. You just focus on that small little bit of code that makes up your domain logic. This is the promise that we got from Lambda and serverless functions and fast, but I've never really seen that backed up with a strong developer experience like we're gonna
13:31 see with Spin today. And this is best developer experience about local and ship into production is why I'm so interested in this space. So as we can see here, it is a framework for building event driven microservice applications with web assembly component. Now this day event driven and that is very important because the spin application, and this comes back to the reason of using Nomad. The Spin application is not just a service that runs perpetually and consistently. A Spin application responds to either a Redis queue, something an end to a Redis queue, or an HTTP request.
14:16 And, looking back to the interview that I had, why Radu was so excited about this model is that they can spin up a WebAssembly module in under a millisecond, which means they provide the HTTP interface, and they provide the Redis interface. And if you have either of those, and under a millisecond, they can launch an entirely new WebAssembly instance of the application, pass in the request, the response, shut it down, clean it up, garbage collect, and it's just done. This is really cool. With FaaS built on top of containers, we've always had to struggle and fight with the
14:49 cold start problem. And the cold start problem again comes back to it takes hundreds of milliseconds to start a container. So I either run these serverless functions on an endless loop and I scale them to what I need and I reuse connections whenever possible. Again, violating this CGI model that we're trying to get to a serverless where everything is handled by its own instant. If that's there to solve that cold start problem. And with WebAssembly, that goes away because the runtime is just that fast. Then you use this wasm time under the hood, which is a WebAssembly runtime written in Rust.
15:28 So I've already installed Spin. The instructions are here. As far as the structure of a Spin application goes, we do have a dot TOML, and then we just have some Rust code. And look at this handler. How nice is this? Now I'm a huge fan of Rust. I'm always talking about Rust, But this is just cool because there's a few things here that are very rusty. Excuse me. I've got terrible cough today. First, we have this macro that surrounds our function. Let's come back to that in a moment and kinda understand what Rust is doing there.
16:00 But our function again has a very simple interface as well. It receives a request that returns a result response. Don't worry about the result if you're not from the Rust ecosystem, it's just an okay triple, but it just takes a request and spits out a response. You know? HTTP in, HTTP out. Then ignoring the okay, which is just again our okay triple, We just say here, wanna return an HTTP response, Rust provides a builder for this. We set the status to 200 and we return hello fermion as a string. We use n two just to cast it into an actual
16:33 string object instead of a Rust more primitive string object regardless, you're gonna note it. And then the question mark is just to do some basic error handling in case any of that fails, which it really shouldn't in this case. So we're only focusing on what we need to relay to the user. This macro is what provides all the boilerplate. This is the procedural macro and injects all the code into this function to make everything work and make sure that the request and response are handled appropriately. Can't don't need to do anything. When we have rust and the ability to do the
17:05 level of meta programming where we use macros to define boilerplate and keep it out of our domain logic applications, we get a very clean interface to build application. And our microservices and the spin environment are many of these. Every issue to be endpoint potentially that we want to handle has an issue to be component function. We can register the path for all of these functions and the spin dot toml and away we go. The manifest itself for the spend dot toml just needs a spend version, a name, and then we can set up the trigger. So
17:38 the trigger at the moment can be HTTP and Redis. They are working on more support and I'm pushing for some cron style scheduling so I can do some weird and cool stuff as well. And you can set a base if you're gonna can, you know, if you wanna compound multiple spin applications together, they all have a different base, but then they all have sub pass within that, you know, the the architecture, the flexibility, whatever you need to do, you can really do. From there, we specify the component and the trigger and away we go. Shouldn't talk so much when I have a
18:09 cough. This is why I have guests so that I can sit in silence for a little bit. Alright. So that's gonna be the basics. If we take a look at the language support, we've got the Rust one which we kinda covered. The only thing you really need to do is Rust up at a target for WASM 32 Wazi. This is all you need to compile any Rust program to VASI and to VASI spec. It works really nice. You can see the exact same code from here, only this time we have to use statements to show that we are pulling on
18:36 the Spin SDK, which provides the HTTP component macro and the request and the response types that we are using within our application. If we pop over to go, things are a little bit similar. Yep. Here we go. We pull in the SDK and the go away way. We have an edit function and a main function. So this is just setting up. So guess it's the yeah. This is our actual response and then the main would have the boilerplate that you would need to handle it. I wonder if that could be done with go generate. I've not actually played with the
19:09 go SDK a whole lot because whenever I see Rust is available, I generally just go straight for Rust. The only time I don't go straight for Rust would be if there was a TypeScript SDK and you can't do spin applications and TypeScript, but I don't think the SDK is there with the abstractions to make things simpler. As far as other languages, they do have a whole bunch of examples. Where's the link? You know what, I am just gonna go get hub, fermions, then there's a examples directory, I'm sure. There we go. And here we can see if we wanna
19:48 take a look at watch. Oh, no. That is just a rust and things. It shows there's a green example somewhere. Yeah. Okay. Yeah. And templates then. If you wanna use green, then we can take a look at the file. We just do print, hello world, and that's enough. If we wanna do something with Zig, which is another really cool language that's coming out in this kind of systems programming space, And we can take a look at this example here. So all we're doing is we don't have the SDK here to mimic the response and request obstructions provided by Rust about
20:27 the the Go SDKs. However, if we think about what a web server is actually doing, which is parsing a string that comes in, which is an HTTP protocol string, which is mostly text based unless it's it's not semantics. I'm not going to right now. And then we spent the text back out. So here we're just saying here's the content header, here's the hello world, and let it handle the rest. So you can kinda do whatever you want as long as your language does support it, but it's probably best to stick to the SDKs. And I do think more SDKs will be
20:57 added into course. And that's just our Swift example. Nice. Alright. We got another question from Russell. Okay. Is it either to have lots of functions on one spin app rather than having lots of spin apps? No. I don't think so. That was just me yapping my mouth too much. I would probably just have a spin application for each endpoint because it's so easy to do. And then a mono repo environment where you can share a whole bunch of type descriptors whatever language they happen to be, whether that whether it's generating from Probus or JSON Schema
21:04 Q&A: Spin App Design Strategy
21:37 or whatever, I would just go down that approach. Spin applications are so lightweight, They're very easy to develop. I've I'd wanna be able to test them in a very easy manner, and I would just have dozens of spin applications rather than lots of functions within a single spin application. It just means that you spin application is gonna get us on different prefix potentially, but, yeah, that's fine. Alright. So let's just see the, you know, I I kinda said at the start here, the developer experience is what's really pushing me to do more of a spin. So let's take a look
21:53 Setting up the Demo: Database with Prisma
22:10 at that. We can run spin new. Let me find a bit bigger. We see all the templates from the repository. Now we've already looked at a few of these. So let's just say we're gonna do we actually did look oh, we never looked at c because why would you? So we can just do h t p c. You can do it with spin new and then just hit return or you can do spin new and then the template name. Here, I'll just say example c spin. We do some stuff. Get a directory. We have our spend dot TOML.
22:52 So this is just the spin version, sets up the offers and description, the h t p trigger with base, and then here is the component. So we're gonna compile our c application to provide something called main dot wasm. We set up the more trigger stuff. Waggy is a is a predecessor to the Fermion platform, but Spin and the Fermion platform can still run Waggy application just fine because the CGI interface has not really changed that much. And then we describe the command used to build it. So again, any language that can compile to WebAssembly, you can
23:29 set a component build command like so. And here we're using Zig to actually compile the c to web assembly, which is a cool new trick. And we get the main dot wasm and it works. But that's pretty boring. So I wanna run through something that I have in playing with. So on the Fermion documentation, one directory too high. So let's go up. Because there's more to this project than the spin up. On the Fairmain documentation, they run you through both my URL shortener. And the URL shortener only accepts static routes. And what I mean by that is it
24:11 only responds to requests with roots that are hard coded. The slash hello returns to here. And that's fine, but being very selfish, I have a use case where I need very static length. Yes. But I also wanna be able to use an API to programmatically create links. And I thought, well, why can't I do this with Spin? So that's what we're gonna take a look at. So the first thing I did because I like to over engineer everything that I do is I set up a Prisma project. In fact, I probably shouldn't do it that
24:47 way. Should change the font size. I was actually coding for a change, so my settings are less livestream ready. I set up a Prisma because I love Prisma. Prisma allows me to describe my database tables and it manages all the migrations for me, applies them to the remote clusters. This is set up to use a local post res right now. However, I did experiment with Prisma against CockroachDB, and it just worked. So we can use Prisma to speak to our database. We describe our models, and it manages the migrations for us. If I pop open the migrations folder,
25:27 we have an SQL statement that says, hey. We're gonna create this redirect table with these fields. And every time I change my Prisma dot schema, I can have it generate a new migration where it calculates what has changed and then always has to kind of upscale and modify your remote database schema, thingy, cluster, postgres, cockroach, whatever, to be the current version. What What I've also been experiment with and I haven't got working yet, but I'm gonna keep hacking on this, is Prisma comes with a concept of a generator. And here, we're actually saying that we're gonna
26:01 just use the provider, which is a command. We're gonna use a cargo command called Prisma, which is actually an alias to run a main dot r s here, which is a Prisma client CLI. So there is no. That's the generic code. So this generator is gonna generate a Rust client to speak to our postgres database or our cockroach DB cloud database. I've had some problems getting it to compile to the was a spec or to a was a target and that's because the Rust client is using some features of Tokyo that aren't compatible yet with the Wazi compilation target.
26:42 I think there's other ways to go around this, but it's gonna require a little bit more time and effort, but I'm gonna keep working on it and hopefully I can share some updates in the coming days and weeks. But we can generate a client. So if we pop open this Prisma.rs, what we have here is a bespoke generated client in Rust to speak to my database with that kind of not like an active record model, but very similar. It gives you the ability to find things very quickly. It gives you the ability to do upsets and inserts and deletes.
27:10 You just got a very good interface to working with your cluster. Here I can see, you know, equals or maybe order something or is it in a vector or is it not in a vector? Is it less than? Exactly. This functional based approach to communicate in a query in a database is very nice. So hopefully I get it working. However, I can run back to my CLI, Docker compose up first because I'm gonna need a database. And this is the very standard Docker compose file. There's no web assembly or enough and then that's the moment. This is just let's
27:44 run Postgres. It's the most recent version, very secure password, and I expose the port locally. That's it. Excuse me. I also have beekeeper, which is a GUI client. Let's pick the databases. And what I'm gonna do, if you can see I already have one fake URL here, is I can just delete all of this. So I'll do it from here. Oh, maybe I can. Docker compose then dash v. This will delete everything and then we'll spin it back up. This should clear any persistence, remove all the databases, and we should start from a clean state just because actually, don't know how to
28:35 delete from beekeeper. I come back here, password. We now have no public and no read write table. Perfect. So from here, I can run PNPX Prisma migrate dev. That just means run my migrations against my dev environment, which is the local postgres. It's executed. And if we jump back over to beekeeper and we hit refresh and we hit refresh, Database is now in sync. Don't lie to me. Alright. Maybe the refresh button doesn't work. Let's try one more time. Hey. Yeah. Don't know why the ref oh, there's another refresh. That refresh is the alright. See, I don't use beekeeper much,
29:39 but it is a nice special way to see this schema. So now we have a reader rest table, which is empty. So let's just add one. And to do this, I do need an ISO 8,601 timestamp because I haven't set up a default default value on the created and updated that schemas, although I really should. I'm just using UTC time dot now where I'm gonna say, okay, fake. It could be my livestream, which is gonna redirect to Twitter.comRawkode. I can see here we wanna do a three zero one and I'm gonna paste in my ISO a six zero one string and
30:20 hit apply. Now we have one entry as part of our dynamic URL shortener in which case that the static words do not match, which I'll show you in just a moment. Go look up something and the postgres database and do a dynamic written to there. So does I need to use Prisma here? No. Is it nice and cool? I mean, I think so. What a couple more things about Prisma. There's lots of generators. So if you wanna generate Rust types, GraphQL schemas, anything like that, there's probably a generator. You just add a little bit of code. This becomes your your your
30:58 source of truth for what your models look like, and then everything else gets generated off the back of it. And I really wanna be able to use this together with my spin application. Excuse me. Okay. So from here, we have our spin application. Here's my spin dot toml. So this is my Rawkode Academy short links project, which hopefully I'll get working and deployed very soon on Fermion Cloud. I'll show you that in a moment. And we can see here, it got a little bit of boilerplate to point it to the target because I'm using cargo workspaces. This
31:10 Exploring the Application Code (Rust)
31:27 has to go up a direction before we go into target. And then we just specify the build command, which is just a cargo build target release. Nice and simple, nothing too strenuous about putting us together and if you use one of their templates, it does it all for you. You don't need to worry about it. From here, we have our lib. Rs. So much like we've seen in the documentation, we're gonna pull in the Spin SDK, which provides request response and issue the component. They also provide some other components, one of them being the ability to speak to Redis
31:59 and the other one being the ability to speak to Postgres. So we're pulling in this p g library so that we can send queries to Postgres. We have our procedural macro that does all the glue for us with this application. We have our function to use as our entry point, and I've got some really crappy debugging on here, which is the print line path, which just tells me the path for each request that comes out to the system. Next, we do a match. So I'm saying, okay. Let's just look at what the path is. And these two here are my static routes.
32:34 I can see yeah. Why not Copilot? Let's do GitHub. What's the name about the name? Trust your thing here and we just do a default redirect for that too. So what is default redirect? Well, let's copy it and do redirect GitHub. And instead of going to the Rawkode Academy website, we're gonna go to github.com, Rawkode Academy. And then we'll change our static rules to be redirect GitHub. Now, of course, this is probably not idiomatic Rust. Would I create a redirect GitHub? No. I'd probably just have a redirect static function that takes a string where I pass in the URL, probably a
33:21 bit cleaner, but just for the sake of moving on with today's demo, we're not gonna bother about that. But what I wanted you to take away is that we can add to this match statement all the static paths that we want. Any URLs that we always want to be shortened in a particular way regardless of what's in the dynamic configuration, which requires a database. We wanna respond really fast and we put them here. But of course we do it in we don't. Of course, we likely want dynamic. So our last part of this match statement
33:51 says, okay. Whatever the other value is, let's just call it path. And when we get a path, we're gonna do some more horrible debugging, which is the exact same debug as the bottom. I'm actually just gonna remove that. I'm gonna trim the slash off of it to make the match a little bit cleaner. You know, we don't in our database want this live to be slash live, we just want it to be live. So we'll just trim it off. So if the string starts with a slash, disappear. Then we have a redirect lookup command. So
34:21 this is the function that goes and speaks to postgres. We pass in the trimmed path and whatever it returned is what we finish with in our function. The fact that there's no colon here or semicolon just means that this is a return value to the match and because the match doesn't have a semicolon, this is just Rust logic here. This is the last expression within the function and it will be returned as our response. So let's pop down to redirect lookup. Excuse me. Now we have a hard coded string here. This is very crappy. I get it.
35:02 Currently, there's not a great way to deploy secrets to Fermion Cloud. However, they are working on it. So just because that's not really there's no primitives yet. There's some things in config I don't wanna dive into just now. I'm gonna do more on that next week. But let's just get this example working. Let's have hard code it and it'll be fine. That was my logic. I hope that makes sense and I'm gonna skip over it for the rest of the session. Then we configure our SQL statement. So how do we find a short link within our database? Well, we
35:38 select long. The only value we actually care about is long and I probably should Let's fix my code and pull back the status code since we have that in beekeeper. Redirect code. Sorry. Redirect code. From the redirect table where short, so that is this key here equals and we're using parameterized SQL statements here, so that we're not vulnerable to SQL or SQL injection attack. And then we use the postgres helper provided by the Spin SDK to query at the address, which we define above the statement, which is our SQL and then any parameters. Now because we have
36:26 a dollar 1, we need exactly one parameter here. So we just use the Spin SDK to say this is a string type and then we pass on the path. If there's an error, we map over there and return that there was an error executing the query. Although we're assuming that it's going to just work because it's a very simple query. Don't expect anything to go wrong. We have one edge case or not really an edge case. We have one case where what if we don't have a URL and a database for that? So for that,
37:01 we return a HTTP response builder status code 404. Hopefully, filters by. Now if we get past that point, we know that we have at least one response. Now at our schema, we actually do specify that our short is an ID. This will make it unique. I wonder if we can see that in Beekeeper. Structure, primary key. Oh, create that. Those have a default value. Okay. It's just update that. If we go to indexes, yep, we have our unique primary key here. So we actually can, hopefully be in a position where we can have two short codes that match. However,
37:52 I just baked the end of the code. So we always pull out zero base because we have that guarantee from a database. That we're never gonna have a one. We don't need to do anything smart. We're just gonna take the first one. We do rules that rules get one at zero, unwrap it, get the index again to get the first column which is our link. We can actually get all of this back and use the redirect code. If I'm feeling brave and we have enough time after we do the DX workflow stuff, maybe we'll do that.
38:21 If this is a string, we return it and if so we do a redirect to the location. And then this is just a little bit of boilerplate that is needed for working with the PG spend SDK. I grab that straight from the docs. I'm just gonna trust that does what it does. Trust that it does what it does. It's just guaranteeing that that or trying to guarantee that if we get column back and we say that we want a string that it is going to be a string and not some other type. Now it's not a lot of code, 70 lines
38:50 Building and Running Spin Locally
38:53 of code. Most of that could be cleaned up. I don't need redirect get hub for a start which takes away nearly 10 lines of code and our lookup could be cleaned up as well, but we're doing, you know, multiple lines to kinda make it fluent and easy to follow. So let's jump over to the terminal. We generated our migration. We run our database. Now we can run spend build. Oh, and the spend directory. This will compile our Rust application, and we will get our Wasm target. If I do target, release oh, no. Where's the And here's somewhere. Oh, wasm
39:48 release. And we have our short links dot wasm file here. We've successfully taken our Rust code, compiled it down to web assembly. And now we can run spin up. Now, it's very fast. And if I if I run spin up again, almost instantaneous. We could probably use hyperfine if this exit, which it doesn't. But that would tell us it started insanely fast. We get a web server on logos 3,000 and it tells us the available routes. So if we were to configure spend to do multiple endpoints which you can, they would be listed here. But what I could do here is say
40:28 curl on just a slash. And I'll do that one more time without the slash to both match to the same. You get a three zero one to the Rawkode Academy and a three zero one to the Rawkode Academy. Let's see if they run hyperfane on this. And I'll need to do Yeah. We're getting our response time over HTTP. Remember, even though it's local host so it's, you know, we can know PEG related to anything like that. But this application is responding with a deviation of about two milliseconds and eight milliseconds. So we're seeing responses anywhere from five point
41:15 six milliseconds. Well, I should have been up to 19, but, you know, the meantime is within two milliseconds of 8.4. So and roughly eight milliseconds we're getting a response over 241 runs. This is on a local machine and it's over a URL that hasn't had in the database and a few other bits of pieces. It's still kinda cool and very very fast. If we do curl and we do blah, blah, blah, we're gonna get an error. Well, there's no complain about my redirect code. And that's because I was feeling too brave. Let remove it. And we just do a spin build and
41:59 I'm just gonna run a spin up. Let's try that one more time. There we go. We get our 404. So what if we run this under hyperfade? Remember this one does have a database lookup because it's not doing a static match and then it does have to speak to postgres to see if there is any match that's still failing and returning no rows. And we can see we're getting a meantime of about twenty five milliseconds. Actually, a bit slower than I was expecting, but still insanely fast for what is actually happening here. So HTTP request, pick the database,
42:37 better response. Not too shabby. And this is that postgres running in a local container on my machine, not optimized or tuned or anything like that. So these numbers are really, really cool. And again, pushing why I am excited about assembly. Let's make this work with our dynamic link, which was live. And we'll see here that we got a three zero one going to twitter.com/Rawkode. Well, I think this is pretty cool, pretty neat. Now for the eagle eyed amongst you, there's one gotcha that I kinda had to work out. And and by work out, I mean, I just
42:51 Local Debugging and Dynamic Route Test
43:17 have to run like a spin up dash dash help. But my log output that we have on the URL match here is nowhere to be seen. So the way that we fix that is to run a follow all on the spin up command. And now when we run our curl, we see our path output here. So as you are working on your spin application locally, which I assume you will be, we can run follow all to get logs to our local terminal. And that's just makes your debugging a lot easier. And you can see even
43:53 with the database, we're still getting twenty five millisecond response time. So what's that dev workflow again looks like just to confirm. Well, we modify our code. We run spin build, spin up, and we run curl to GitHub too. And we got our 240 odd responses. 266 this time. There we go. Static links in eight milliseconds. That is pretty sweet. So that's the demo. I like the dev experience. I like the simplicity of the functions. We're relying on Rust's procedural macros to mean that I only write the code that I care about. I like that they provide libraries for speaking
44:01 Deployment to Fermion Cloud
44:41 to postgres and Redis. I wanna do more with that. I'm really eager for them to do some sort of secrets management because really what I wanna do is after I've done my my spend build and spills up spend up, is we have the access to a spend deployment, and we just run this. And we get a link back with a production URL for all of our traffic. But here, I have a fermion. App and I'm gonna run hyperfine again, but inject my new URL, which is delivered over TLS for free. All those things don't look as good. However,
45:32 Fairmount Cloud is hosted in US East 1 and I am in Europe. So the latency at minimum is probably gonna be about three hundred millisecond. But we had 10 requests to the remote server that responded and just to show this oh, I copied that by mistake. Just to show you the headers here on the response. There's why it's so slow. Let's try it IPv6 first. So let's do that again with dash four. Yeah. Much faster. And we get redirect to get hub Rawkode Academy. So lots of really cool things here. Spend build, edit code, spend build, spend up
46:17 for local development, spend deploy, throw it to Fermion Cloud for free, get TLS, get custom domain names, all this other cool stuff. I'm gonna be doing a lot more with this entire platform because I really wanna push this URL shortener to do my own bedding rather than Ryan on relying on services with Bitly. And another really cool idea I've got is I wanna build my own analytics engine, like Google Analytics, but using just WebAssembly and request. Because I reckon we could do some pretty neat stuff in the browser and on the server get a really key piece
46:48 of analytic experience. And I'm gonna push that as far as I can go. I'm gonna jump back to monologue phase, check for any questions, but I hope you like what you've seen and hopefully your interest is peaked and you can check out Spin and WebAssembly. You got a question from Moz. Does Rust follow TypeScript syntax? They have some similarities for sure. They're both modern languages that have learned a lot. They provide strict typing. They have functional constructs, you know, the ability to map, reduce, etcetera. They have error handling. So there's a lot of things that are very similar. But I'd
46:51 Final Q&A and Conclusion
47:26 say the Rust syntax is more esoteric. TypeScript is a lot more familiar to people. Coming from Caesar relative languages and JavaScript, it'll feel very yeah. Or even Java, it will feel good and easy to understand. TypeScript, with procedural macros the unwrapping of everything and lifetimes takes a little bit more effort. But if you see similarities with TypeScript, that's good. Don't let the scary stuff scare you away. So Russell said, so was it created a new connection for each request? I got a phone call so missed them in the video and still responding in only twenty five milliseconds.
48:05 Yeah. The span run time only launches the wasm binary when a request comes in that matches the endpoint, the route that you have it configured to. Everything that you're seeing is the spend run time, the fermion platform, which is also open source by the way. You can go to fermion. Github.com/fermion. You'll find the platform open source repository. You can run it yourself on a EC two instance on Equinix metal or GCP, whatever you want. Pass it some WASM files and away it goes. And so, yeah, you're getting a unique instance of that web that web assembly
48:38 application for every request or every Redis message within the cluster. Cool. Alright. It looks like there are no more questions. Thank you for joining me today. As I said, I'll be doing a lot more with WebAssembly, and make sure you tune in for the next episode. Thank you again. Have a wonderful evening.
Technologies featured
Meet the Cast
Stay ahead in cloud native
Tutorials, deep dives, and curated events. No fluff.
Comments