---
# System prepended metadata

title: 'Design: Streaming Verbs'
tags: [in-review]

---

# Design: Streaming Verbs
**Author**: Stuart Douglas

## Description (what)

We should support Verbs that can handle a stream of data, so that the full request / response does not need to fit in memory.

## Motivation (why, optional)

At present FTL can only handle data that arrives in a single request and fits enteirly in memory. There are many use cases that require streaming data (e.g. downloading large files). This will be particularly important for AI which relies on large datasets that are likely to large to handle with our current verb architecture.

A core use case for this is to handle large HTTP requests / response that we don't want to load into memory, or long running websocket requests.

## Goals

This should allow verbs to send and receive streams of data, within the scope of a single method invocation (i.e. the verb call does not return until the streams are done). Verbs can send a recieve a single 'chunk' of data at a time, where each chunk is a normal FTL type defined by the schema.

### Non-Goals (optional)

Reactive / Async stream processing is out of scope (e.g. the verb call returns, but events are generated by the stream and handled by a worker thread). This is only really relevant to Java, and will likely become even less relevant as loom gets better.

## Design (how)

The schema shall introduce a new FTL type, `stream[T]`. This can be used as a request/response types for verbs, and can also be embedded into a type declaration. A type declaration can have at most a single stream type embedded in it.

In Go a stream is represented as a channel. In Java/Kotlin it is represented as an `java.util.Iterator<T>`.

A streaming HTTP request could look something like:

```
type StreamingHttpRequest[Body any, Path any, Query any] struct {
  Method string `json:"method"`
  Path string `json:"path"`
  PathParameters Path `json:"pathParameters"`
  Query Query `json:"query"`
  Headers map[string][]string `json:"headers"`
  Body <-chan Body
}
```

Note that all the non-streaming parts of the type are essentually considers the headers, and will be sent before any streaming data.

This is all mapped to the schema as normal, however any type that embeds a streaming type will have additional metadata added to the schema to indicate that it is a stream, and any verb that has a streaming type as a request or response type will also have additional metadata indicating it is a streaming verb.

To invoke streaming verbs an additional CallStreaming method will be added to the `VerbService`, that will allow for the request and response to be streamed.

Async verbs such as cron jobs and topic subscriptions are not allowed to be streaming.

For response streaming once the initial payload is returned the runtime will continue to read from the channel/`Iterator` until either the channel is closed or the iterator `hasNext` method returns `false`. For go this will generally involve spawing a gorouting to write to the channel in the background after the verb has returned. For Kotlin this generally means providing a custom implementation of `Iterator` that will load more data in the hasNext method.

### Open Questions

- How is this represented in the timeline?
