고객을 온보딩하기 위해 다시 시작하지 않고 .NET 워크플로 엔진의 멀티 테넌트 SaaS

작성자

카테고리:

← 피드로
DEV Community · Optimajet Limited · 2026-07-23 개발(SW)

The most expensive restart in SaaS is often the one nobody planned: onboarding a new customer. Every SaaS team expects adding a tenant to be a database operation. I still see production systems where it is a deployment.

I am Mike Lukinov, co-founder of Optimajet. In July 2026 we shipped Workflow Engine by Optimajet version 22.0.0, and for SaaS teams it changes the thing that matters most: tenants become runtime objects instead of startup configuration. Tenants register and unregister while the host is running, and multi-tenancy is finally full and hybrid, meaning every layer of engine data can be tenant-scoped or shared, side by side in one installation.

Here is the scene that drove this work. Last month I spoke with a team running about 150 enterprise tenants on .NET. Everything worked, until sales signed one more customer. Their onboarding checklist contained the line “restart production”. Every restart window interrupted other tenants’ approvals mid-flight. That was not a workflow problem, it was an architecture problem.

This post is the announcement written the way I explain it on architecture calls: what a SaaS team should demand from a .NET workflow engine, and how the new version answers it. I mark each block as Documented behavior, Architectural recommendation, or Honest limitation, so you can separate facts from my opinion.

What a multi-tenant SaaS needs from a workflow engine

Architectural recommendation. When teams evaluate an enterprise workflow engine for SaaS, they usually compare designers and API surfaces. The tenancy questions surface later, in the security review, and they are the expensive ones. Five of them matter most:

  1. Can shared and tenant-specific data live side by side, or is tenancy all-or-nothing?
  2. Can I add a tenant without redeploying or restarting anything?
  3. Is tenant isolation enforced by the engine and its API, or by discipline in my own code?
  4. Does isolation cover all engine data, or only the process table?
  5. Can I adopt tenancy gradually, or does it require a data migration on day one?
Capability Why it matters Hybrid tenancy Shared standard workflows plus per-tenant custom ones Runtime tenant registration No production restart to onboard a customer API-enforced tenant isolation Leaks blocked by the engine, not by code review Isolation across all data Audit compliance: history and inboxes, not just processes Gradual adoption No day-one migration project

Hold any engine you evaluate against these five. The rest of this post is how Workflow Engine NEO answers them.

Question 1: can shared and tenant-specific data live side by side

Documented behavior. The engine now implements full hybrid multi-tenancy. Every kind of engine data (workflow schemes, Global Parameters, forms, process records) exists in one of two forms: shared and visible to every tenant, or scoped to one tenant. A record with an empty tenant value is shared; a record created in a tenant context carries that tenant’s ID. The Forms Plugin resolves a tenant-specific form first and falls back to the shared one.

Shared (no tenant ID)
├── Standard workflow schemes
├── Shared forms
└── Global Parameters
        │ visible to every tenant
   ┌────┴─────────┬───────────────┐
Tenant A       Tenant B        Tenant C
processes      processes       custom scheme
history        history         custom forms
inbox          inbox           processes, history

Enter fullscreen mode Exit fullscreen mode

Architectural recommendation. This hybrid model matches how a SaaS grows. One standard approval flow serves most customers; the accounts that pay for custom routing get multi-tenant workflows scoped to them, in the same installation. The alternative, a separate deployment per customized customer, is how SaaS margins die.

Question 2: runtime tenant onboarding while the host is running

Documented behavior. Per the release notes, retrieved 2026-07-21, the tenant registry accepts changes at runtime. This is the dynamic tenant registration piece:

// A new customer signs up. Register them as a tenant, at runtime:
var tenantRegistry = services.GetRequiredService<IWorkflowTenantRegistry>();

var tenants = await tenantRegistry.RegisterTenantsAsync(new WorkflowTenantCreationOptions
{
    TenantIds = ["TenantA"],
    PersistenceProviderId = PersistenceProviderId.Mssql,
    ConnectionString = connectionString
});

// No restart. Existing tenants keep processing their workflows.
var tenant = tenants.Single();

// Offboarding is the same call in reverse. The host keeps running.
await tenantRegistry.UnregisterTenantsAsync(tenant);

Enter fullscreen mode Exit fullscreen mode

Registry-managed tenants start automatically and shut down gracefully when removed. If your application owns tenant lifecycle itself, mark them with WorkflowTenantLifecycleOwnership.External and the registry skips the automatic lifecycle calls. Reads stay consistent while the list changes: IWorkflowTenantSnapshot gives request code an immutable, point-in-time view of registered tenants.

Architectural recommendation. Runtime tenant onboarding becomes one call in your provisioning code, next to creating the tenant database and issuing credentials. Onboarding turns into a database operation, not a deployment event.

Question 3: who enforces tenant isolation

Documented behavior. The tenant boundary is enforced by the API layer, not by convention. A Data API request for another tenant’s process returns a not-found result. RPC endpoints check the process tenant against the current HTTP tenant and reject cross-tenant commands. My favorite detail: rpc/is-process-exists answers false for a process that belongs to another tenant. One tenant cannot even probe whether another tenant’s data exists.

The same version closes a quieter hole: system Global Parameter types (security settings, LDAP configuration, CORS settings, and similar) are no longer reachable through generic Data API operations.

Architectural recommendation. The tenant header selects context, it does not grant access. Authorization still comes from the WorkflowApiPermissions claim. I wrote about scoping those claims per caller in When to use Data API vs RPC API in Workflow Engine NEO; everything there still holds, now with tenant isolation enforced underneath it.

Question 4: how deep the isolation goes

Documented behavior. Tenant isolation now covers everything the engine stores: schemes, Global Parameters, forms, and every process-related record, from statuses and timers to transition history, inbox entries, and approval history. The Forms Plugin runs tenant-aware on Form Engine 10.0.1.

Architectural recommendation. The record types at the end of that list are the ones to check in any engine you evaluate. Schemes and processes get the attention, but transition history, inbox entries, and approval history are what your auditor asks about, and they leak tenant activity just as well as a process record does. Isolation that stops at the process table is not isolation.

Question 5: what happens to the data you already have

Documented behavior. Nothing changes on its own. Existing records have no tenant value, so under the hybrid model from Question 1 they are shared and stay visible across tenants, exactly as they behaved before the upgrade. Only new records created in a tenant context get a tenant ID.

Architectural recommendation. Upgrade first, then adopt tenancy at the pace your contracts demand, not the pace your engine dictates. Keep standard schemes shared, scope the customer-specific ones, and let historical process data age out as shared records.

Honest limitations

I would rather you hear these from me than from your own upgrade weekend.

  • 22.0.0 is a breaking release. The tenant contract changed (custom IWorkflowTenant implementations need lifecycle members), several IPersistenceProvider signatures now take a tenant ID, and the AssignmentPlugin was removed. Database migrations are mandatory: SQL providers run RunMigrations() before starting the updated runtime, MongoDB needs the update_22.0.0.js index script run manually. The release notes pair every breaking change with a migration scenario. Budget a real upgrade task, not a version bump.
  • The Web API and full multi-tenancy are licensed NEO features. Workflow Engine is commercial software with a free tier, source-available under a commercial EULA, not open source, and the Web API does not start without a license key. A trial key from trial.workflowengine.io lets you evaluate it; the free Community Edition covers the embeddable in-process library, not the Web API.
  • Runtime registration does not provision infrastructure. RegisterTenantsAsync registers a tenant against a connection string you supply. Creating the database, running its schema, and storing its secrets remain your provisioning code’s job.

Version note

Everything above targets Workflow Engine 22.0.0 (July 16, 2026), verified against the official release notes and the NuGet registry (WorkflowEngine.NETCore-Core 22.0.0) on 2026-07-21. On 21.x and earlier the tenant list is static and the data-layer scoping described here does not exist; do not read this article as documentation for those versions.

The questions are older than the release

Most workflow engine evaluations still focus on designers, BPMN coverage, and APIs. In SaaS, the tenant lifecycle becomes the real architectural bottleneck much later, when changing the answer is already expensive. The five questions above are worth asking before that day arrives, whichever workflow engine for SaaS you end up choosing.

If you want to check our answers against your own architecture, the upgrade details are on our blog, and my team does demo walkthroughs where we build the argument on your tenancy model, not ours.

원문에서 계속 ↗

코멘트

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다