# Multiple Processes

> Run the Document Editor backend in the application container or in its own container: DocumentEditorWorkerManager, worker processes and Docker Compose.

- **Product:** TX Text Control .NET Server
- **Section:** Documentation
- **Kind:** Topic
- **Path:** TX Text Control .NET Server > Deployment Guide > Docker > Multiple Processes
- **2823 words**
- **Web URL:** https://docs.textcontrol.com/tx-text-control-dotnet-server/deployment/docker/multiple-processes/
- **LLMs URL:** https://docs.textcontrol.com/tx-text-control-dotnet-server/deployment/docker/multiple-processes/llms.txt
- **LLMs-Full URL:** https://docs.textcontrol.com/tx-text-control-dotnet-server/deployment/docker/multiple-processes/llms-full.txt

---

An application with the Document Editor is more than one process. Next to your ASP.NET Core application runs the backend `TXTextControl.Web.Server.Core`, which synchronizes the editing sessions, and the backend starts a worker process for every editor that connects. In containers, you decide whether the backend shares the container of your application or runs in a container of its own.

Both layouts are described below: what runs where, how the application and the backend find each other and what happens when one of them stops. Applications without the Document Editor, which only process documents or use the Document Viewer, run as a single process and need none of this.

### The Processes of an Application

```text
dotnet MyApp.dll                                  your application, the entry point of the container
  |
  +-- dotnet TXTextControl.Web.Server.Core.dll    the backend, started by DocumentEditorWorkerManager
        |
        +-- dotnet TXTextControl.Web.Server.Core.Process.dll   one worker process for each open editor
```

- **Your application** hosts the WebSocket middleware, which passes the traffic of each editor over TCP to the backend. `ServerTextControl`, `MailMerge` and the Document Viewer work inside this process and start no other processes.
- **The backend** listens on TCP port 4283 by default and starts the worker processes. It communicates with them over pipes, which need no ports.
- **A worker process** holds the document of one editing session in memory until your code saves it. It ends when the editor closes or when a lost connection isn't restored in time.

The hosted service `DocumentEditorWorkerManager` starts the backend when your application starts and stops the backend and all worker processes when the application shuts down. It doesn't restart a backend that ends on its own: the application keeps running, and editors can't connect until the application restarts.

### Choose Where the Backend Runs

|  | In the application container | In its own container |
|---|---|---|
| Setup | `AddHostedService<DocumentEditorWorkerManager>()`, nothing else | A second image, and the address of the backend in the application |
| Scaling | Application and backend scale together | The backend scales separately from the application |
| When a container stops | Application, backend and editing sessions stop together | The sessions in a stopped backend container end; the application keeps running |
| Use it for | Most applications | Deployments that separate real-time editing from the application, as Text Control recommends for many concurrent users |

[Scaling Beyond One Instance](https://docs.textcontrol.com/tx-text-control-dotnet-server/overview/architecture/#scaling-beyond-one-instance) describes Text Control's recommendation for larger deployments.

### Run the Backend in the Application Container

The image from [Dockerfile](https://docs.textcontrol.com/tx-text-control-dotnet-server/deployment/docker/dockerfile/llms-full.txt) already runs the backend: the application starts it inside the container, and the backend's messages appear in the container output with the prefix `[TXTextControl.Web.Server.Core]`.

Without configuration, the backend listens on all network interfaces of the container, and it accepts TCP connections from any client. Other containers in the same network could connect to port 4283. Bind the backend to the loopback address of the container instead, with the address and port in the `DocumentEditorWorker` configuration section and the same values in *Program.cs*, as [Prepare the Application](https://docs.textcontrol.com/tx-text-control-dotnet-server/deployment/linux/ubuntu/#prepare-the-application) shows. In a container, environment variables set the section, with two underscores in place of the colon:

```bash
docker run --rm -p 8080:8080 \
  -e DocumentEditorWorker__ListenAddress=127.0.0.1 \
  -e DocumentEditorWorker__Port=4283 \
  myapp
```

The application log then shows "Listen address "127.0.0.1" provided via options." and the backend "Starting TCP listener on port 4283 for IPv4.".

### Run the Backend in Its Own Container

A separate backend needs its own image, a listen address that other containers can reach and an application that connects to it by name.

#### Create the Backend Project

The backend image contains the backend files, the Core engine it uses and their native libraries and fonts. A class library that references the two packages publishes all of them. Create *Backend/Backend.csproj* next to the folder of your application:

```xml
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net10.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="TXTextControl.TextControl.Core.SDK" Version="34.0.5" />
    <PackageReference Include="TXTextControl.Web.DocumentEditor.Backend" Version="34.5.0" />
  </ItemGroup>

</Project>
```

The project needs no code. Use the same package versions as your application.

#### Build the Backend Image

Create *Backend/Dockerfile*. It follows the Dockerfile of the application and starts the backend instead:

```dockerfile
# syntax=docker/dockerfile:1

FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src

COPY Backend/Backend.csproj Backend/
RUN --mount=type=secret,id=nugetconfig \
    dotnet restore Backend/Backend.csproj -r linux-x64 --configfile /run/secrets/nugetconfig

COPY Backend/ Backend/
RUN dotnet publish Backend/Backend.csproj -c Release -r linux-x64 --self-contained false \
    --no-restore -o /app/publish

FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS final
WORKDIR /app
COPY --from=build /app/publish .
USER $APP_UID
EXPOSE 4283
ENTRYPOINT ["dotnet", "TXTextControl.Web.Server.Core.dll", "--listen-address", "0.0.0.0", "--port", "4283"]
```

`--listen-address 0.0.0.0` makes the backend reachable from the application container, and `--port` sets its port. Build both images from the folder that contains *nuget.config*, the *Dockerfile* of the application and the two project folders:

```bash
docker buildx build --secret id=nugetconfig,src=nuget.config -t myapp .
docker buildx build -f Backend/Dockerfile --secret id=nugetconfig,src=nuget.config -t mybackend .
```

#### Connect the Application to the Backend

The application doesn't start a backend of its own. Remove `AddHostedService<DocumentEditorWorkerManager>()` from *Program.cs* and pass the name and port of the backend to the middleware:

```csharp
using TXTextControl.Web;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();

var app = builder.Build();

app.UseRouting();

app.UseWebSockets();

// Connect the editors to the backend container
app.UseTXWebSocketMiddleware("backend", 4283);

app.UseAuthorization();

app.MapStaticAssets();
app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}")
    .WithStaticAssets();

app.Run();
```

The code works as follows:

- `UseTXWebSocketMiddleware("backend", 4283)` resolves the host name `backend` to an address once, when the application starts, and connects every editor to this address and port.
- If the name can't be resolved at that moment, the application doesn't start. The log shows a `SocketException` thrown in the constructor of `TXTextControl.Web.WebSocketMiddleware`.
- If the backend isn't running when an editor connects, the editor doesn't load, and the browser console shows "WebSocketHandler.DoTalkingAsync(): Could not connect to TextControl TCP server" with the address and port.

#### Start Both With Docker Compose

A *compose.yaml* file starts both containers in one network, in which each service is reachable by its name:

```yaml
services:
  app:
    image: myapp
    ports:
      - "8080:8080"
    depends_on:
      - backend

  backend:
    image: mybackend
    expose:
      - "4283"
    restart: unless-stopped
```

The file works as follows:

- **`backend`** is the service name that the application passes to `UseTXWebSocketMiddleware`.
- **`expose`** makes port 4283 reachable for the other services without publishing it on the host. Don't add a `ports` entry for the backend.
- **`depends_on`** starts the backend before the application, so its name exists when the application resolves it.
- **`restart: unless-stopped`** restarts the backend container when the backend process ends. Editing sessions of the ended process are lost.

A backend container that is recreated can get a new address. Because the application resolved the name at startup, restart the application container as well.

When an editor connects, the output of the backend container shows "Starting web editor worker process with connection ID" followed by the ID of the connection.

### Next Steps

- [Scaling Containers](https://docs.textcontrol.com/tx-text-control-dotnet-server/deployment/docker/scaling/llms-full.txt): run several application and backend containers.
- [Kubernetes](https://docs.textcontrol.com/tx-text-control-dotnet-server/deployment/kubernetes/llms-full.txt): run the containers in a cluster.
- [Document Editor Architecture](https://docs.textcontrol.com/tx-text-control-dotnet-server/document-editor/architecture/llms-full.txt): the backend, its configuration file and the life of an editing session.
- [WebSocket Architecture](https://docs.textcontrol.com/tx-text-control-dotnet-server/integration/websockets/llms-full.txt): the connection between the browser, the middleware and the backend.

---

## Nearby

- **Previous:** [Fonts](https://docs.textcontrol.com/tx-text-control-dotnet-server/deployment/docker/fonts/llms-full.txt)
- **Next:** [Scaling Containers](https://docs.textcontrol.com/tx-text-control-dotnet-server/deployment/docker/scaling/llms-full.txt)
