Back

Inngest Development Server

2023 - Product Design

Inngest Dev Server

Problem

Event-driven architecture is a software paradigm where a system communicates via the emission and ingestion of events. Events normally capture a change in state, whether that be automated or user-initiated. For example, when a user completes the checkout flow on an eCommerce website, a checkout.complete event may be emitted, allowing developers to attach related workflows (creating a shipping order, sending the user a "checkout completed" email etc).

Inngest provides a solution to this with fantastic DX, removing the need for users to create queues, workers, or manage complex state themselves. Writing event-driven functions is difficult without the ability to run, and debug, them locally though. Developers need to be able to interact with Inngest's queueing system to understand how their functions will operate in a live setting.

Proposed Solution

With Event-Driven Architecture often being relatively novel for web-based software engineers, succinctly conveying the power of Inngest with only a live environment is a challenging sell. Users signing up to the Inngest Cloud Platform were presented with an empty experience, prompting such questions as:

  • How do I send events to Inngest?
  • How do I write functions that Inngest can call?
  • Where do I deploy my functions?
  • How do I know if my functions are working?

There are several steps involved with getting a live function working, and it can often be seen as too daunting of a task. To help fix this, a local version of Inngest should be created that developers can use in order to help them debug their serverless functions. It should run on users' own machines, providing instant visual feedback and debugging tools so they can quickly develop and iterate on their function workflows.

This acts as both a developer tool, and to some extent, and education piece. Showing the power of Event-Driven Architecture in practice is often more valuable than being bogged down by the theory behind it, so the Inngest Dev Env should guide developers through creating their own functions and seeing them in action, taking their knowledge and understanding from 0 to 1 quickly.

Time Constraints

For Inngest, as an early-stage startup, growth is everything. As mentioned before, a large blocker for users when getting started with Inngest is that initial 0 to 1. The sooner we can get users to that 1, the sooner they can start building out their own workflows and understand the value of Inngest.

In terms of external factors, Vercel's promotion of their serverless functions played a large role. The initial intention was for Inngest to host its users' functions itself. Not only is this expensive and a lot of extra overhead to manage, there are a lot of existing solutions that already offer robust serverless function hosting. As Inngest functions are invoked via HTTP, where these functions were hosted is arbitrary. Inngest only needs to know where it should point itself in order to call them. Piggybacking on the Vercel announcements would mean we would get more exposure for Inngest. It, more importantly though, would actually provide an easy-to-use solution to the regular problems of managing serverless function calls.

Based on this, we initially scoped three weeks for this project.


Starting with a command

To remove friction when getting started with Inngest, the local dev environment is launched via a single CLI command, npx inngest-cli dev.

10:26AM INF executor > service starting
10:26AM INF devserver > autodiscovering locally hosted SDKs
10:26AM INF runner > starting event stream backend=redis
10:26AM INF runner > service starting 10:26AM INF devserver > service starting
10:26AM INF executor > subscribing to function queue
10:26AM INF api > starting server addr=0.0.0.0:8288
10:26AM INF runner > subscribing to events topic=events
Inngest dev server online at 0.0.0.0:8288, visible at the following URLs:
- http://127.0.0.1:8288 (http://localhost:8288)
- http://192.168.0.135:8288
- http://10.5.0.2:8288
Scanning for available serve handlers.
To disable scanning run `inngest dev` with flags: --no-discovery -u <your-serve-url>

The CLI shows Inngest booting and running the dev server. By providing the dev server URLs, it informs and guides developers into launching the dev tool.

Information Hierarchy

It was important to visually establish the relationship between events and functions. In Inngest, functions are triggered by sending events. Whilst functions can emit events of their own, the journey originates when an event is received by Inngest, with a function running as a result.

Inngest Flow

We wanted the UI to reflect this flow in order to help user to understand how information passes through Inngest. Building a UI around this meant breaking down each part of this flow and presenting them separately.

Events are sent to Inngest via HTTP and are agnostic of their source. Once they have been received, they're added to the internal queue and executed sequentially. As events are agnostic of source, anything can emit them. Inngest is uninterested in where they came from, only that it has received them.

Inngest Flow

Rapidly prototyping based on this hierarchy naturally led to a three column layout—one for each of the internal steps that Inngest handles:

  • Event Ingestion
  • Event Instance & Function calls
  • Individual function runs & their output
Inngest Flow

Event Ingestion

The first column focuses on event ingestion, displaying a live feed of events being received. This provides a high-level overview of data flowing into Inngest, acting as a jumping-off point for users to start debugging their functions.

Each feed item displays an overview of the most relevant information for a single event's journey:

  • The Event Name that Inngest has received.
  • The Timestamp at which it was received at.
  • The number of functions that event triggers.
  • The overall state of all functions triggered.
Inngest Dev Server

Inngest can handle a phenomenal number of events per second, so it's important for users to be able to digest everything happening in their system at a glance. Pulling out the most important information provides an immediate decision point for users, preventing them from having to drill down through each event to see the current execution state of the triggered functions.


Event Instance & Function Calls

The Event Instance column provides all relevant information for a single event instance. Alongside the Name of the function, the time Inngest received it and the specific ID of that event is displayed.

Inngest Dev Server

Each event can trigger n number of function—a single function just has to be listening for a particular event name. Each resulting function call runs independently, with its own state and outcome. Similar to the Event Ingestion feed, providing an overview of all functions triggered by a single event instance helps developers understand the result of their emitted events.

Every event Inngest receives can have an optional payload attached—stateless JSON that a function can use in its execution. Displaying this provides visibility to the data each of the called functions is executing, aiding with debugging.

Function Card

The Function Card, like the event feed items, provides a high-level overview of a single function instance. Functions can have state in Inngest. They can be queued, processed, paused, and cancelled based on developer interaction with the UI, or via another event. Displaying the current status of a function allows developers to see what, if anything, has broken.

Inngest Dev Server
  • Name & ID captures the function name and the ID of the single run instance.
  • Timestamp, displaying exactly when a function started executing.
  • The Function Version shows the version of code the function contains—as a user develops their functions, different versions can have arbitrarily different outcomes.
  • Function Status shows what's happening internally with its execution.

The Function Card also contains inline feedback for the user, in the form of a message and action. As shown in the card example above, this function run has been paused. The inline message informs the user about the current status, and the action provides them with the next logical step based on that status—in this case, resuming the function's execution.


Function Run & Output

The Function Run column contains all relevant information for a single function instance. It expands on the cards found in the Event Instance column, providing in-depth information about the function's execution. The top of the column displays the relevant information for that instance, including metadata for its status, version, queue & execution time, and any output the function may have.

Inngest Dev Server

Execution Timeline

The Execution Timeline displays an information-rich log of the function instance's execution. This granulated view ensures developers can look "under the hood" of their function to check if it is working as intended and understand each moment of its execution.

Inngest Dev Server

Empty States

Developer environments are often without data when first initialised. It is important to guide the user from 0 to 1, informing them of the next logical step to complete. These should be unobtrusive though, as users who are well versed with the development tool just want to get on with their workflow and start debugging. Displaying empty states is a super-easy way to handle this. The environment itself and each column has its own empty state, helping to alleviate any points a user can become stuck. This also provides the perfect place to embed relevant documentation links, ensuring developers can read more about what they need to do next.

Inngest Dev ServerInngest Dev Server

Building the Front-end

Code, and particularly front-end styling, is just an extension of the design process. Due to the time constraints, the visual designs were deliberately not made pixel-perfect, but designed just enough to provide a base to dive into the build. Using React, I built out the front-end, including UI animations and interactions. This ensured the interactive UX matched what I had in mind whilst creating the static mockups, and allowed the engineer to take the completed React components and connect them up to Inngest's core with ease.


Confident Brushstrokes

Launching a product quickly will inevitably constrain the feature set. However, releasing an initial version, even if imperfect, allows us to gather invaluable user feedback. This approach doesn't always suit larger organisations, which often need extensive research and testing in order to have a more stable broad deployment. But for startups, regularly updating the product and adapting to user feedback is crucial for ensuring we develop features that truly meet their needs at the right moment.

Decisions need to be made quickly and there's often little time to weigh up the best course of action. It's far better to commit to an idea and see it through than to mull over three or four different iterations. Those can come later.

Inngest Dev Server