tourze/digital-ocean-droplet-bundle
A Symfony bundle that integrates DigitalOcean Droplet management into your application, providing configuration, dependency injection wiring, and service classes for creating, listing, and controlling droplets through the DigitalOcean API.
Release 0.1.0 ships no human-readable changelog — the notes are just a 0.0.3...0.1.0 compare link. Treat this as an initial assessment of the package, not a validated upgrade path, and budget 20 minutes to read the diff before adopting it.
Steps:
composer require tourze/digital-ocean-droplet-bundle — then immediately check vendor/tourze/digital-ocean-droplet-bundle/composer.json for an extra.laravel.providers block. The -bundle suffix is Symfony heritage; if there is no Laravel service provider, you must register the bundle's entry class manually in config/app.php (or in a small wrapper provider of your own).README.md → src/ (find the manager/client class and the DTO/model directory) → tests/ (the fastest way to see real call signatures) → the compare link for what changed in 0.1.0.config/packages/*.yaml; Laravel-native packages expect a publishable config/*.php. Check for vendor:publish tags — if none exist, the config is constructor-injected and you configure it via a binding..env (e.g. DIGITALOCEAN_TOKEN), never in a committed config file, and confirm which env key the bundle actually reads rather than assuming.Wrap it, don't sprinkle it. Bind the package's service in a dedicated DigitalOceanServiceProvider and inject it into one thin application-level gateway class (DropletGateway). Controllers, jobs, and commands talk to your gateway, not the vendor class. This is what makes the inevitable 0.x breaking changes a one-file edit.
Separate read and write paths.
Cache::remember(..., now()->addDay(), ...). Droplet lists get a short TTL (30–60s) so a dashboard isn't hammering the API.$timeout well above the HTTP default, and $tries of 2–3 with backoff. Only retry transport failures and 5xx/429 — a 422 on a bad payload will never succeed.Tag at creation, query by tag. Pass DigitalOcean tags on the create call (app:acme, env:prod, tenant:42). Reconciling by tag is far more robust than persisting droplet IDs alone, and it survives a lost row in your database.
Provisioning workflow. Create → the API returns an action, not a ready droplet → poll the action (or the droplet's status) until active and an IP is assigned → run your user-data/cloud-init → persist the ID → a scheduled droplets:reconcile command compares DO state against your droplets table and flags drift. DigitalOcean does not push state to you; if you want fast feedback, poll on a schedule and cache the result.
Testing. Never hit the live API. If the bundle is built on Laravel's HTTP client, Http::fake() with recorded fixtures works; if it wraps its own transport, bind a fake implementation of the client interface in the test container. Assert your gateway's behaviour, not the vendor's.
Multi-account / multi-region. Register the service as a non-singleton or keyed binding per token rather than one global instance — a singleton will leak credentials across tenants in a multi-tenant app.
0.0.3 in composer.json and diff the compare link before upgrading; commit the lockfile.Retry-After on 429s and use exponential backoff rather than a fixed sleep.status alone will give you false "active" readings during resize.TypeError that reads like a package bug but is a calling-code bug.app()->isProduction()) plus a confirmation prompt — --force in a local script pointed at prod is the classic incident.X-Request-Id / ratelimit-remaining response headers — DigitalOcean support asks for the request ID. Dump the hydrated DTO, not the raw PSR-7 response; the raw body is noisy and often already consumed."^0.1" with a committed lockfile over "*", and re-read the compare link on every bump.How can I help you explore Laravel packages today?