(ctx context.Context, vol *ApplicationVolume, progress DeployProgressCallback)
| 301 | } |
| 302 | |
| 303 | func (a *Application) deployWithVolume(ctx context.Context, vol *ApplicationVolume, progress DeployProgressCallback) error { |
| 304 | if progress != nil { |
| 305 | progress(DeployProgress{Stage: DeployStageStarting}) |
| 306 | } |
| 307 | |
| 308 | id, err := ContainerRandomID() |
| 309 | if err != nil { |
| 310 | return fmt.Errorf("generating container id: %w", err) |
| 311 | } |
| 312 | |
| 313 | containerName := fmt.Sprintf("%s-app-%s-%s", a.namespace.name, a.Settings.Name, id) |
| 314 | |
| 315 | env := a.Settings.BuildEnv(vol.Settings) |
| 316 | |
| 317 | hostConfig := &container.HostConfig{ |
| 318 | RestartPolicy: container.RestartPolicy{Name: container.RestartPolicyAlways}, |
| 319 | LogConfig: ContainerLogConfig(), |
| 320 | Mounts: a.volumeMounts(vol), |
| 321 | } |
| 322 | hostConfig.Resources = container.Resources{ |
| 323 | Memory: int64(a.Settings.Resources.MemoryMB) * 1024 * 1024, |
| 324 | NanoCPUs: int64(a.Settings.Resources.CPUs) * 1e9, |
| 325 | } |
| 326 | |
| 327 | resp, err := a.namespace.client.ContainerCreate(ctx, |
| 328 | a.containerConfig(env), |
| 329 | hostConfig, |
| 330 | &network.NetworkingConfig{ |
| 331 | EndpointsConfig: map[string]*network.EndpointSettings{ |
| 332 | a.namespace.name: {}, |
| 333 | }, |
| 334 | }, |
| 335 | nil, |
| 336 | containerName, |
| 337 | ) |
| 338 | if err != nil { |
| 339 | return fmt.Errorf("creating container: %w", err) |
| 340 | } |
| 341 | |
| 342 | if err := a.namespace.client.ContainerStart(ctx, resp.ID, container.StartOptions{}); err != nil { |
| 343 | a.namespace.client.ContainerRemove(ctx, resp.ID, container.RemoveOptions{Force: true}) |
| 344 | return fmt.Errorf("starting container: %w", err) |
| 345 | } |
| 346 | |
| 347 | shortContainerID := resp.ID[:12] |
| 348 | |
| 349 | if err := a.namespace.Proxy().Deploy(ctx, DeployOptions{ |
| 350 | AppName: a.Settings.Name, |
| 351 | Target: shortContainerID, |
| 352 | Host: a.Settings.Host, |
| 353 | TLS: a.Settings.TLSEnabled(), |
| 354 | }); err != nil { |
| 355 | a.namespace.client.ContainerRemove(ctx, resp.ID, container.RemoveOptions{Force: true}) |
| 356 | if strings.Contains(err.Error(), "target not healthy") || strings.Contains(err.Error(), "deploy timed out") { |
| 357 | slog.Error("Application failed to start", "app", a.Settings.Name, "error", err) |
| 358 | return ErrAppNotStarted |
| 359 | } |
| 360 | return fmt.Errorf("registering with proxy: %w", err) |
no test coverage detected