Skip to content

Implement own Service Manager client for separate-bucket multitenancy #810

@Schmarvinius

Description

@Schmarvinius

Context

For separate-bucket multitenancy, the OSS module currently relies on the @cap-js/attachments MTX sidecar plugin to handle tenant onboarding/offboarding (creating/deleting per-tenant object store instances and bindings via the Service Manager API). The Java app only has a read-only SM client for runtime credential resolution (getBinding()).

This works but couples us to the JS plugin for a critical lifecycle operation, and we lose control over:

  • Bucket content cleanup on unsubscribe (JS sidecar only deletes the SM instance/binding, doesn't empty the bucket first)
  • Cache warming on subscribe (first request after provisioning hits a cold cache)
  • Error resilience (orphaned instance cleanup on binding failure, resilient unsubscribe that continues after partial failures)

Goal

Implement a full Service Manager client in the Java OSS module that handles the complete tenant lifecycle independently, without requiring @cap-js/attachments in the MTX sidecar.

Scope

SM Client (write operations)

  • createInstance(tenantId, planId) — create object store instance with polling for async completion
  • createBinding(tenantId, instanceId) — create service binding
  • deleteBinding(bindingId) — delete service binding
  • deleteInstance(instanceId) — delete instance with async polling
  • getOfferingId() / getPlanId(offeringId) — discover objectstore offering and plan (standard / s3-standard)

Lifecycle Orchestration

  • Subscribe handler (DeploymentService.EVENT_SUBSCRIBE): idempotency check → create instance → create binding → warm client cache. Clean up orphaned instance if binding fails.
  • Unsubscribe handler (DeploymentService.EVENT_UNSUBSCRIBE): delete bucket contents → evict cache → delete binding → delete instance. Errors logged but don't block flow.

Token Provider

  • OAuth2 client credentials flow + mTLS support
  • In-memory token caching with refresh margin

Registration

  • Wire SM client, lifecycle handler, and subscribe/unsubscribe event handlers in Registration.registerSeparateMode()
  • Service Manager binding discovery from CdsEnvironment

Notes

  • The existing read-only getBinding() in ServiceManagerClient can be extended rather than rewritten
  • Both standard and s3-standard plans should be supported (try standard first, fall back to s3-standard)
  • Labels: tenant_id: [tenantId], service: ["OBJECT_STORE"]
  • Reference implementation: cap-js/attachments lib/mtx/server.js

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions