Tilt

repository·master·Indexed 11 days ago

https://github.com/tilt-dev/tilt

A tool for microservice development that automates the feedback loop by watching for file changes, building container images, and automatically updating Kubernetes-based development environments.

Tokens
35K
Snippets
153
Records
183
Agent score
84%

What's inside Tilt

  1. Concurrency and Dispatching in the Tilt Store

    master

    When interacting with the Tilt Store, developers must account for the following concurrency behaviors:

    • Synchronized OnChange: A subscriber's OnChange method is synchronized. The Store will not invoke OnChange on a specific subscriber again until the previous OnChange execution has completed.
    • Asynchronous Dispatch: Calling store.Dispatch(action) is non-blocking. The action is placed into a FIFO queue, and the function returns immediately.
    • Action Batching: The Store typically processes actions in batches after a backoff period.
    • State Skipping: Because actions are batched, subscribers should not assume they will receive an OnChange call for every single individual action. For example, if a resource is created and then immediately deleted, the resulting actions might be grouped together, and a subscriber might only see the final state (the resource being gone) without ever seeing the intermediate 'created' state.
  2. How the Tilt control loop works

    master

    Tilt operates as a continuous control loop driven by four primary components:

    1. EngineState: The central source of truth representing everything Tilt knows about the current environment.
    2. Store: The mediator that manages changes to the EngineState.
    3. Subscribers: Components that read from the Store. When the state changes, the Store calls OnChange on each subscriber. Subscribers then diff the new state against their previous state to determine what work to perform (e.g., starting a log stream or watching a new Kubernetes pod).
    4. Actions: Objects created by subscribers that represent requested state changes. Subscribers use store.Dispatch(action) to request these changes.

    The Lifecycle: State Change $\rightarrow$ Store calls OnChange on Subscribers $\rightarrow$ Subscribers perform work and Dispatch new Actions $\rightarrow$ Store applies Actions to EngineState $\rightarrow$ Process repeats.

  3. Run Tilt integration tests using kind

    master

    If you want to run the Tilt integration tests against a single-use, isolated Kubernetes cluster instead of your existing cluster, you can use kind. This is the method used in CircleCI to ensure a clean environment.

    Run the following command to create a kind cluster and execute the tests:

    make integration-kind
  4. Run Tilt to start your development environment

    master
    To start working in a complete development environment configured for your team, run the tilt up command. Tilt automates the workflow from code changes to updated processes by watching files, building container images, and updating your environment (similar to docker-compose up but optimized for microservices).
    tilt up
  5. Run Tilt integration tests

    master

    Tilt integration tests run the Tilt binary to ensure services are correctly deployed. These tests require kubectl to be configured to communicate with an existing Kubernetes cluster. The framework compiles the Tilt binary and deploys servers to the tilt-integration namespace.

    Note: The tilt-integration namespace is not deleted automatically after the tests complete.

    To run the tests against your existing cluster, use one of the following commands:

    go test -tags 'integration' -timeout 30m ./integration
    make integration

    These tests are excluded from the standard make test command.

  6. Organize Tiltfiles using Starlark and `load_dynamic`

    master

    Tiltfiles are written in Starlark, a Python-inspired language. This allows you to use standard programming constructs like functions, conditionals, and loops. For large projects, you can organize logic by loading other Tiltfiles.

    • Use load_dynamic(path) to load a Tiltfile at a specific path.
    • Use watch_file(path) to ensure Tilt re-evaluates when that file changes.
    • Use os.path.exists(path) to check for file existence.

    For more details on organizing logic, see https://docs.tilt.dev/tiltfile_concepts.html and https://docs.tilt.dev/multiple_repos.html.

    def tilt_demo():
        if os.path.exists('tilt-avatars/Tiltfile'):
            load_dynamic('tilt-avatars/Tiltfile')
        watch_file('tilt-avatars/Tiltfile')
        git_checkout('https://github.com/tilt-dev/tilt-avatars.git', 
                     checkout_dir='tilt-avatars')
  7. Configure readiness probes for commands

    master

    You can define a ReadinessProbe for a command to ensure it is considered 'Ready' only after a specific check passes. The probe supports two types of handlers:

    1. Exec Action: Runs a command within the environment. The command's exit code determines success (0) or failure (non-zero).
    2. HTTP Get Action: Performs an HTTP GET request to a specified port. A successful response indicates readiness.

    If a probe configuration is invalid (e.g., a port number out of range), the command will fail to start and report a termination error.

    localTarget.ReadinessProbe = &v1alpha1.Probe{
        TimeoutSeconds: 5,
        Handler: v1alpha1.Handler{
            Exec: &v1alpha1.ExecAction{Command: []string{"sleep", "15"}},
        },
    }
  8. Understand statusAndMetadata updates

    master

    When using an Execer, the statusAndMetadata struct is sent through the status channel to communicate the state of a command. Key fields include:

    • status: The current state (e.g., Running, Done, Error).
    • pid: The process ID of the running command.
    • exitCode: The exit code returned by the process (0 for success, non-zero for errors).
    • reason: A string describing why the process stopped (e.g., "killed", or an error message).
  9. Identify Tilt CLI subcommands

    master

    The Tilt CLI is organized into several subcommands that control different aspects of the development lifecycle. Based on the internal dependency wiring, the primary subcommands include:

    • up: Starts the Tilt development loop, watching for changes and deploying resources.
    • down: Stops the Tilt development loop and cleans up resources.
    • ci: Runs Tilt in a Continuous Integration mode (optimized for non-interactive environments).
    • updog: A specialized mode (likely for specific resource monitoring or interactive debugging).
    • tiltfile: Commands related to evaluating or interacting with the Tiltfile.
    • docker-prune: Commands for cleaning up Docker resources.
    • lsp: Language Server Protocol support for Tiltfiles.

    Note: For a full list of available commands and their specific flags, run tilt --help in your terminal.

  10. How the Cmd controller manages command lifecycles

    master

    The Cmd controller is responsible for reconciling v1alpha1.Cmd objects by executing them as local processes. It manages the lifecycle through several key mechanisms:

    • Execution Triggers: Commands can be triggered by StartOn or RestartOn specifications. The controller watches for changes in these triggers (like UI button clicks or specific events) to decide whether to start a new process or restart an existing one.
    • Spec Changes: Any change to the CmdSpec (arguments, environment variables, directory, etc.) causes the controller to stop the currently running process and restart it to ensure the new configuration is applied.
    • Disabling Commands: If cmd.Spec.DisableSource is set to a disabled state, the controller stops the process and resets the internal tracking of start/restart events.
    • Readiness Probes: If a ReadinessProbe is defined in the spec, the controller manages a probeWorker that monitors the process. The CmdStatus.Ready field is updated based on the probe results (prober.Success or prober.Warning mark the command as ready).
    • Status Updates: The controller continuously synchronizes the internal process state (Running, Terminated, Waiting, Ready) with the v1alpha1.CmdStatus in the Kubernetes API.

    Note: Commands managed by local_resource or cmd_image annotations are currently handled differently and do not trigger automatic deployment via reconciliation.