diff --git a/src/content/docs/containers/container-package.mdx b/src/content/docs/containers/container-package.mdx index 147ae4ebb8a4e7d..7ab2262d88b4d64 100644 --- a/src/content/docs/containers/container-package.mdx +++ b/src/content/docs/containers/container-package.mdx @@ -45,3 +45,50 @@ such as: See the [Containers GitHub repo](https://github.com/cloudflare/containers) for more details and the complete API. + +## Starting containers + +When working with containers, you have two main methods for starting them: + +### `startAndWaitForPorts()` (recommended) + +This method starts the container and waits until your application is ready to accept connections on the specified ports. Use this method to ensure your application is fully initialized before sending requests. + +```javascript +const container = env.MY_CONTAINER.getByName("session-123"); +await container.startAndWaitForPorts(); +return container.fetch(request); +``` + +This is the recommended approach because it prevents errors that occur when attempting to connect to a container that has not finished starting up. + +**When to use**: Use this method when you need to ensure the container application is ready before proceeding. This is especially important when routing requests to specific container instances. + +**Performance**: Adds a couple hundred milliseconds during cold starts, which is expected and necessary. This overhead only occurs when starting a new container instance, not on subsequent requests. + +### `start()` + +This method starts the container but does not wait for your application to be ready. The container begins booting immediately, but your application may not yet be listening on its ports. + +```javascript +const container = env.MY_CONTAINER.getByName("session-123"); +await container.start(); +// May fail if application is not ready yet +return container.fetch(request); +``` + +**When to use**: Only use this method if you do not need to immediately connect to the container, or if you want to start a container without blocking until ports are available. + +**Caution**: Using `start()` followed immediately by `fetch()` may result in connection errors if your application has not finished initializing. + +### Using `fetch()` directly + +For most use cases, you can call `fetch()` directly on the container without manually calling `startAndWaitForPorts()`. The `fetch()` method automatically handles starting the container and waiting for ports to be ready: + +```javascript +const container = env.MY_CONTAINER.getByName("session-123"); +// fetch() handles starting and waiting for readiness +return container.fetch(request); +``` + +Refer to [troubleshooting documentation](/containers/troubleshooting/#container-not-listening-on-tcp-address) for more details on container startup patterns. diff --git a/src/content/docs/containers/faq.mdx b/src/content/docs/containers/faq.mdx index 7aec2e5e4c7f70d..11ffda8b55c002a 100644 --- a/src/content/docs/containers/faq.mdx +++ b/src/content/docs/containers/faq.mdx @@ -9,6 +9,14 @@ import { WranglerConfig } from "~/components"; Frequently Asked Questions: +## Why am I getting "container is not listening" errors? + +If you see an error like `Error proxying request to container: The container is not listening in the TCP address 10.0.0.1:8080`, this means your Worker attempted to send a request to a container that has not finished starting up. + +Use `startAndWaitForPorts()` to ensure your container application is ready before making requests, or call `fetch()` directly on the container (which automatically waits for ports to be ready). + +Refer to the [troubleshooting guide](/containers/troubleshooting/#container-not-listening-on-tcp-address) for detailed solutions. + ## How do Container logs work? To get logs in the Dashboard, including live tailing of logs, toggle `observability` to true diff --git a/src/content/docs/containers/troubleshooting.mdx b/src/content/docs/containers/troubleshooting.mdx new file mode 100644 index 000000000000000..26ee03b48e04ff0 --- /dev/null +++ b/src/content/docs/containers/troubleshooting.mdx @@ -0,0 +1,273 @@ +--- +pcx_content_type: troubleshooting +title: Troubleshooting +sidebar: + order: 9 +--- + +import { Tabs, TabItem } from "~/components"; + +This guide covers common issues you may encounter when using Containers and how to resolve them. + +## Container not listening on TCP address + +### Error message + +```txt +Error proxying request to container: The container is not listening in the TCP address 10.0.0.1:8080 +``` + +### Problem + +This error occurs when your Worker attempts to send a request to a container that has not finished starting up. The container status may show as healthy, but the application inside the container is not yet ready to accept connections on the specified port. + +This commonly happens when using `binding.get()` to retrieve a container instance and immediately calling `fetch()` without waiting for the application to be fully initialized. + +### Solution + +Use `startAndWaitForPorts()` instead of `start()` to ensure your container application is ready before making requests. + + + + +```javascript +import { Container } from "@cloudflare/containers"; + +export class MyContainer extends Container { + defaultPort = 8080; + sleepAfter = "10m"; +} + +export default { + async fetch(request, env) { + const container = env.MY_CONTAINER.getByName("session-123"); + + // Ensure the container is started and port 8080 is ready + await container.startAndWaitForPorts(); + + // Now safe to send requests + return container.fetch(request); + }, +}; +``` + + + + +```javascript +import { Container } from "@cloudflare/containers"; + +export class MyContainer extends Container { + defaultPort = 8080; + sleepAfter = "10m"; +} + +export default { + async fetch(request, env) { + const container = env.MY_CONTAINER.getByName("session-123"); + + // Only starts the container, does not wait for application readiness + await container.start(); + + // May fail if application is not ready yet + return container.fetch(request); + }, +}; +``` + + + + +### Understanding the difference + +- **`start()`**: Starts the container but does not wait for your application to be ready. The container begins booting, but your application may not yet be listening on its ports. + +- **`startAndWaitForPorts()`**: Starts the container and waits until the specified ports are ready to accept connections before returning. This ensures your application is fully initialized. + +### Performance considerations + +Using `startAndWaitForPorts()` may add a couple hundred milliseconds of overhead during cold starts. This is expected and necessary behavior - there is a natural delay between when the container runtime starts and when your application is ready to serve requests. + +This overhead only occurs during: + +- **Cold starts**: When a container instance is started for the first time +- **Rollouts**: When a container is restarted due to deployment updates +- **Host shutdowns**: When a container needs to be restarted on a different host + +Subsequent requests to an already-running container do not incur this overhead. + +## Container lifecycle best practices + +### When to use fetch() directly + +The `fetch()` method on a container automatically starts the container if it is not already running and waits for ports to be ready. For most use cases, you can call `fetch()` directly without manually calling `startAndWaitForPorts()`: + +```javascript +export default { + async fetch(request, env) { + const container = env.MY_CONTAINER.getByName("session-123"); + // fetch() handles starting the container and waiting for readiness + return container.fetch(request); + }, +}; +``` + +### When to manually start containers + +You may want to explicitly call `startAndWaitForPorts()` when: + +- You need to perform initialization logic after the container starts but before sending requests +- You want to start multiple containers in parallel before making requests +- You need fine-grained control over the startup process + +```javascript +export default { + async fetch(request, env) { + const container = env.MY_CONTAINER.getByName("session-123"); + + // Manually start and wait + await container.startAndWaitForPorts(); + + // Perform custom initialization + await container.containerFetch("/health"); + + // Now handle the actual request + return container.fetch(request); + }, +}; +``` + +### Checking multiple ports + +If your container application exposes multiple ports that need to be ready, specify them when calling `startAndWaitForPorts()`: + +```javascript +await container.startAndWaitForPorts({ + ports: [8080, 9090], +}); +``` + +## Container takes long time to start + +### Problem + +Container instances take several seconds to start on first request. + +### Explanation + +Container cold starts typically take 2-3 seconds, but this depends on: + +- Image size +- Application initialization time +- Resource requirements + +This is expected behavior for containers, which have longer cold start times compared to Workers. + +### Solutions + +1. **Keep containers warm**: Set an appropriate `sleepAfter` value to keep containers alive longer between requests: + +```javascript +export class MyContainer extends Container { + defaultPort = 8080; + sleepAfter = "30m"; // Keep container alive for 30 minutes of inactivity +} +``` + +2. **Use load balancing**: Distribute requests across multiple container instances to reduce the impact of cold starts: + +```javascript +import { getRandom } from "@cloudflare/containers"; + +export default { + async fetch(request, env) { + // Route to one of 5 container instances + const container = await getRandom(env.MY_CONTAINER, 5); + return container.fetch(request); + }, +}; +``` + +3. **Optimize your container image**: Reduce image size and minimize application startup time. + +## Container stops unexpectedly + +### Problem + +Container instances shut down even though you are actively using them. + +### Explanation + +Containers automatically sleep after the timeout specified by `sleepAfter` if they do not receive requests or have their activity timeout renewed. + +### Solution + +Ensure you set an appropriate `sleepAfter` value for your use case: + +```javascript +export class MyContainer extends Container { + defaultPort = 8080; + sleepAfter = "1h"; // Adjust based on your needs +} +``` + +For background tasks that do not involve HTTP requests, manually renew the activity timeout: + +```javascript +export class MyContainer extends Container { + defaultPort = 8080; + sleepAfter = "10m"; + + async performBackgroundTask() { + // Do some work... + + // Renew the timeout to prevent sleep + await this.renewActivityTimeout(); + } +} +``` + +## Container logs not appearing + +### Problem + +Container logs are not visible in the Containers Dashboard. + +### Solution + +Enable observability in your `wrangler.toml` or `wrangler.json` configuration: + +```json +{ + "observability": { + "enabled": true + } +} +``` + +Refer to [Container logs documentation](/containers/faq/#how-do-container-logs-work) for details on retention periods and costs. + +## Container out of memory errors + +### Problem + +Container instances restart with Out of Memory (OOM) errors. + +### Solution + +1. **Choose a larger instance type**: Select an instance type with more memory. Refer to [instance types documentation](/containers/platform-details/limits/#instance-types). + +2. **Optimize memory usage**: Review your application code to reduce memory consumption. + +3. **Monitor memory usage**: Add logging to track memory consumption in your container application. + +Containers do not use swap memory, so you must ensure your application fits within the instance's memory limits. + +## Getting additional help + +If you continue to experience issues: + +- Review the [Container examples](/containers/examples/) for reference implementations +- Check the [Containers FAQ](/containers/faq/) for common questions +- Visit the [Cloudflare Discord](https://discord.cloudflare.com) and ask in the Containers channel +- Review the [Container class documentation](https://github.com/cloudflare/containers) on GitHub