Skip to content

WIP: Add workload scheduling backup#303

Draft
techkuz wants to merge 1 commit into
yandex:mainfrom
techkuz:MDB-32451
Draft

WIP: Add workload scheduling backup#303
techkuz wants to merge 1 commit into
yandex:mainfrom
techkuz:MDB-32451

Conversation

@techkuz
Copy link
Copy Markdown

@techkuz techkuz commented Mar 24, 2026

https://clickhouse.com/docs/operations/workload-scheduling

Summary by Sourcery

Add backup and restore support for ClickHouse workload scheduling entities (WORKLOADs and RESOURCEs) for servers running ClickHouse 24.11 and later.

New Features:

  • Support backing up ClickHouse workload entities (WORKLOADs and RESOURCEs) from local or ZooKeeper storage, including optional decryption.
  • Support restoring workload entities from backups, updating or recreating existing entities when definitions differ.
  • Include workload entities in backup metadata and storage layout alongside existing objects like named collections.
  • Expose configuration for workload entity storage location and type, with a default local workload path.

Tests:

  • Add integration scenarios verifying backup and restore of RESOURCE and WORKLOAD entities, including schema-only mode and handling of pre-existing entities with the same name.

@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented Mar 24, 2026

Reviewer's Guide

Adds backup and restore support for ClickHouse workload scheduling entities (WORKLOADs and RESOURCEs), including storage abstraction (local/ZooKeeper, optional encryption), metadata tracking, layout and control-plane operations, and integration tests.

Sequence diagram for workload entities backup flow

sequenceDiagram
    participant User
    participant CHBackup
    participant BackupSources
    participant BackupContext
    participant WorkloadEntitiesBackup
    participant ClickhouseControl
    participant ClickhouseConfig
    participant WorkloadEntitiesStorageConfig
    participant BackupMetadata
    participant BackupLayout
    participant ClickHouseEncryption
    participant ZookeeperCTL
    participant Storage

    User->>CHBackup: backup(sources)
    CHBackup->>BackupSources: for_backup(..., workload_entities=true, ...)
    CHBackup->>WorkloadEntitiesBackup: backup(context)

    WorkloadEntitiesBackup->>ClickhouseControl: ch_version_ge("24.11")
    ClickhouseControl-->>WorkloadEntitiesBackup: bool
    alt version < 24.11
        WorkloadEntitiesBackup-->>CHBackup: return
    else version >= 24.11
        WorkloadEntitiesBackup->>WorkloadEntitiesStorageConfig: from_ch_config(ch_ctl_conf, ch_config)
        WorkloadEntitiesStorageConfig-->>WorkloadEntitiesBackup: we_config

        WorkloadEntitiesBackup->>ClickhouseControl: get_workload_entities_query()
        ClickhouseControl-->>WorkloadEntitiesBackup: workload_entities:list
        alt no workload entities
            WorkloadEntitiesBackup-->>CHBackup: return
        else workload entities exist
            loop for each entity_name
                WorkloadEntitiesBackup->>BackupMetadata: add_workload_entity(entity_name)
            end

            WorkloadEntitiesBackup->>WorkloadEntitiesStorageConfig: is_local_storage()
            alt local storage
                WorkloadEntitiesBackup->>Storage: copy_directory_content(storage_path, backup_tmp_path)
            else zookeeper storage
                WorkloadEntitiesBackup->>ZookeeperCTL: _copy_directory_content_from_zookeeper(...)
                ZookeeperCTL->>Storage: read nodes into backup_tmp_path
            end

            WorkloadEntitiesBackup->>WorkloadEntitiesStorageConfig: is_encrypted()
            alt encrypted
                WorkloadEntitiesBackup->>ClickHouseEncryption: decrypt_directory_content(backup_tmp_path, key_hex)
                ClickHouseEncryption->>Storage: decrypt files
            end

            loop for each entity_name
                WorkloadEntitiesBackup->>BackupLayout: upload_workload_entity_ddl_from_file(local_path, backup_name, entity_name)
                BackupLayout->>Storage: upload_file(encrypted)
            end
        end
    end
Loading

Sequence diagram for workload entities restore flow

sequenceDiagram
    participant User
    participant CHBackup
    participant BackupSources
    participant BackupContext
    participant WorkloadEntitiesBackup
    participant ClickhouseControl
    participant BackupMetadata
    participant BackupLayout

    User->>CHBackup: restore(sources)
    CHBackup->>BackupSources: for_restore(..., workload_entities=true, ...)
    CHBackup->>WorkloadEntitiesBackup: restore(context)

    WorkloadEntitiesBackup->>ClickhouseControl: ch_version_ge("24.11")
    ClickhouseControl-->>WorkloadEntitiesBackup: bool
    alt version < 24.11
        WorkloadEntitiesBackup-->>CHBackup: return
    else version >= 24.11
        WorkloadEntitiesBackup->>BackupMetadata: get_workload_entities()
        BackupMetadata-->>WorkloadEntitiesBackup: we_list
        alt we_list empty
            WorkloadEntitiesBackup-->>CHBackup: return
        else we_list not empty
            WorkloadEntitiesBackup->>ClickhouseControl: get_workload_entities_query()
            ClickhouseControl-->>WorkloadEntitiesBackup: we_on_clickhouse_list

            loop for each entity_name in we_list
                WorkloadEntitiesBackup->>BackupLayout: get_workload_entity_create_statement(backup_meta, entity_name)
                BackupLayout-->>WorkloadEntitiesBackup: statement

                alt entity exists on ClickHouse
                    WorkloadEntitiesBackup->>BackupLayout: get_local_we_create_statement(entity_name)
                    BackupLayout-->>WorkloadEntitiesBackup: we_on_clickhouse_statement or null
                    alt statements differ
                        WorkloadEntitiesBackup->>ClickhouseControl: drop_workload_entity(entity_name)
                        ClickhouseControl->>ClickhouseControl: try DROP WORKLOAD then DROP RESOURCE
                        WorkloadEntitiesBackup->>ClickhouseControl: restore_workload_entity(statement)
                    else statements equal
                        Note over WorkloadEntitiesBackup,ClickhouseControl: No action taken
                    end
                else entity missing on ClickHouse
                    WorkloadEntitiesBackup->>ClickhouseControl: restore_workload_entity(statement)
                end
            end
        end
    end
Loading

Class diagram for workload entities backup and related structures

classDiagram
    class BackupMetadata {
        -List~str~ _workload_entities
        +add_workload_entity(entity_name: str) void
        +get_workload_entities() List~str~
        +dump(light: bool) dict
        +load(data: dict) BackupMetadata
    }

    class WorkloadEntitiesBackup {
        +backup(context: BackupContext) void
        +restore(context: BackupContext) void
        +get_workload_entities_list(context: BackupContext) List~str~
        -_copy_directory_content_from_zookeeper(zk_ctl: ZookeeperCTL, from_path_dir: str, to_path_dir: str) void
    }

    class WorkloadEntitiesStorageConfig {
        +storage_type: StorageType
        +storage_path: str
        +encryption_key_hex: str
        +is_local_storage() bool
        +is_storage_zookeeper() bool
        +is_encrypted() bool
        +from_ch_config(ch_backup_config: dict, ch_config: ClickhouseConfig) WorkloadEntitiesStorageConfig
    }

    class StorageType {
        <<enumeration>>
        LOCAL
        LOCAL_ENCRYPTED
        ZOOKEEPER
        ZOOKEEPER_ENCRYPTED
    }

    class BackupSources {
        +access: bool
        +data: bool
        +schema: bool
        +udf: bool
        +named_collections: bool
        +workload_entities: bool
        +for_backup(access: bool, data: bool, schema: bool, udf: bool, named_collections: bool, workload_entities: bool, schema_only: bool) BackupSources
        +for_restore(access: bool, data: bool, schema: bool, udf: bool, named_collections: bool, workload_entities: bool, schema_only: bool) BackupSources
        +schemas_included() bool
    }

    class ClickhouseControl {
        +get_workload_entities_query() List~str~
        +restore_workload_entity(entity_statement: str) void
        +drop_workload_entity(entity_name: str) void
        +ch_version_ge(version: str) bool
    }

    class BackupLayout {
        +upload_workload_entity_ddl_from_file(local_path: str, backup_name: str, entity_name: str) void
        +get_local_we_create_statement(entity_name: str) str
        +get_workload_entity_create_statement(backup_meta: BackupMetadata, filename: str) str
    }

    class BackupContext {
        +backup_meta: BackupMetadata
        +backup_layout: BackupLayout
        +ch_ctl: ClickhouseControl
        +ch_ctl_conf: dict
        +ch_config: ClickhouseConfig
        +zk_ctl: ZookeeperCTL
    }

    class CHBackup {
        -_we_backup_manager: WorkloadEntitiesBackup
        +backup(sources: BackupSources, databases: dict) void
        +_restore(sources: BackupSources) void
    }

    class ZookeeperCTL {
        +zk_client
        +zk_root_path: str
    }

    class ClickhouseConfig {
        +config: dict
    }

    class BackupManager
    class ClickHouseEncryption

    WorkloadEntitiesBackup ..|> BackupManager
    WorkloadEntitiesStorageConfig o-- StorageType

    WorkloadEntitiesBackup --> BackupContext
    WorkloadEntitiesBackup --> WorkloadEntitiesStorageConfig
    WorkloadEntitiesBackup --> ClickHouseEncryption
    WorkloadEntitiesBackup --> ZookeeperCTL

    BackupContext --> BackupMetadata
    BackupContext --> BackupLayout
    BackupContext --> ClickhouseControl

    CHBackup --> WorkloadEntitiesBackup
    CHBackup --> BackupSources

    BackupMetadata --> BackupLayout

    ClickhouseControl --> BackupLayout
Loading

Flow diagram for workload entities storage configuration selection

flowchart TD
    A["Start from_ch_config"] --> B["Read workload_entity_storage from ClickhouseConfig"]
    B --> C{"workload_entity_storage present?"}

    C -- "No" --> D["Read workload_path from ch_backup_config"]
    D --> E{"workload_path set?"}
    E -- "No" --> F["Assert error: workload_path missing"]
    E -- "Yes" --> G["Create WorkloadEntitiesStorageConfig with<br/>storage_type=LOCAL<br/>storage_path=workload_path<br/>encryption_key_hex=''"]
    G --> Z["Return config"]

    C -- "Yes" --> H["Read type, path, key_hex from workload_entity_storage"]
    H --> I{"type present?"}
    I -- "No" --> J["storage_type=LOCAL"]
    I -- "Yes" --> K["storage_type=StorageType(type)"]

    J --> L["storage_path=path"]
    K --> L
    L --> M["encryption_key_hex=key_hex"]
    M --> N["Create WorkloadEntitiesStorageConfig(storage_type, storage_path, encryption_key_hex)"]
    N --> Z
Loading

File-Level Changes

Change Details Files
Introduce workload entity backup/restore pipeline integrated with existing backup flow, gated by ClickHouse version >= 24.11.
  • Add WorkloadEntitiesBackup manager that reads workload entity DDLs from local filesystem or ZooKeeper (with optional encryption), uploads them into backup storage, and restores them with conflict handling when entities already exist.
  • Wire WorkloadEntitiesBackup into ch_backup backup/restore entrypoints controlled by the new BackupSources.workload_entities flag and default it on when nothing specific is requested.
  • Guard workload-entity operations with a ch_version_ge('24.11') check and log when unsupported.
ch_backup/ch_backup.py
ch_backup/backup/sources.py
ch_backup/logic/workload_entities.py
Extend backup layout and ClickHouse control abstractions to handle workload entities as first-class metadata objects.
  • Add workload_path configuration and layout helpers to read local workload entity DDL files and to upload/download them from backup storage under a workload_entities/ directory.
  • Expose ClickHouse-side operations for workload entities: querying system.workloads and system.resources, executing CREATE DDL, and robustly dropping entities by trying WORKLOAD then RESOURCE.
  • Track workload entity names in BackupMetadata, persisting them in backup metadata JSON and providing add/get helpers.
ch_backup/backup/layout.py
ch_backup/clickhouse/control.py
ch_backup/backup/metadata/backup_metadata.py
ch_backup/config.py
Add configuration and tests for workload entities storage and behavior.
  • Define WorkloadEntitiesStorageConfig to describe storage type (local/ZooKeeper, encrypted/plain) and derive it from ClickHouse config or ch-backup workload_path.
  • Implement a small ZooKeeper directory copy helper to fetch workload entity files during backup.
  • Add integration feature tests to validate RESOURCE/WORKLOAD restore, conflict overwrite semantics, and schema-only backup/restore for workload entities.
ch_backup/logic/workload_entities.py
tests/integration/features/workload_entities.feature

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@techkuz techkuz changed the title Add workload scheduling backup WIP: Add workload scheduling backup Mar 24, 2026
Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 4 issues, and left some high level feedback:

  • In WorkloadEntitiesStorageConfig.from_ch_config, when workload_entity_storage is present but path is missing, storage_path can become None without any validation; consider asserting or raising a clear error if path (and when required, key_hex) are absent to avoid hard-to-debug runtime issues.
  • In ClickhouseCTL.drop_workload_entity, you currently fall back to dropping a RESOURCE on any Exception from the WORKLOAD drop; it would be safer to restrict the fallback to expected errors (e.g. entity-not-found) rather than swallowing all failures, so that real errors (permissions, syntax, connectivity) are not masked.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `WorkloadEntitiesStorageConfig.from_ch_config`, when `workload_entity_storage` is present but `path` is missing, `storage_path` can become `None` without any validation; consider asserting or raising a clear error if `path` (and when required, `key_hex`) are absent to avoid hard-to-debug runtime issues.
- In `ClickhouseCTL.drop_workload_entity`, you currently fall back to dropping a RESOURCE on any `Exception` from the WORKLOAD drop; it would be safer to restrict the fallback to expected errors (e.g. entity-not-found) rather than swallowing all failures, so that real errors (permissions, syntax, connectivity) are not masked.

## Individual Comments

### Comment 1
<location path="ch_backup/backup/layout.py" line_range="347-354" />
<code_context>
+                local_path, remote_path=remote_path, encryption=True
+            )
+        except Exception as e:
+            msg = f"Failed to create async upload of {remote_path}"
+            raise StorageError(msg) from e
+
</code_context>
<issue_to_address>
**suggestion:** Error message mentions 'async upload' although the call is synchronous, which can mislead debugging.

Since `upload_file` is used synchronously, this message is misleading for anyone reading logs or debugging. Please update it to describe the actual failure (for example, `Failed to upload workload entity DDL to {remote_path}`) without implying async behavior.

```suggestion
        try:
            logging.debug('Uploading workload entity create statement "{}"', entity_name)
            self._storage_loader.upload_file(
                local_path, remote_path=remote_path, encryption=True
            )
        except Exception as e:
            msg = f"Failed to upload workload entity DDL to {remote_path}"
            raise StorageError(msg) from e
```
</issue_to_address>

### Comment 2
<location path="ch_backup/clickhouse/control.py" line_range="1006-1008" />
<code_context>
+        remote_path = _workload_entities_data_path(
+            self.get_backup_path(backup_name), entity_name
+        )
+        try:
+            logging.debug('Uploading workload entity create statement "{}"', entity_name)
+            self._storage_loader.upload_file(
</code_context>
<issue_to_address>
**issue (bug_risk):** Catching a broad Exception when dropping workload entities may hide real errors.

Because any `DROP WORKLOAD` failure is treated as “must be a RESOURCE”, unrelated errors (permissions, syntax, connection issues, etc.) get silently misclassified and retried. If ClickHouse provides a specific code or message for “WORKLOAD not found”, please check for that explicitly before falling back to `DROP RESOURCE`, and re-raise all other errors.
</issue_to_address>

### Comment 3
<location path="ch_backup/logic/workload_entities.py" line_range="233-234" />
<code_context>
+            return WorkloadEntitiesStorageConfig(storage_path=storage_path)
+
+        storage_type_from_config = we_config.get("type")
+        storage_path_from_config = we_config.get("path")
+        encryption_key_hex_from_config = we_config.get("key_hex")
+
+        storage_type = WorkloadEntitiesStorageConfig.StorageType.LOCAL
</code_context>
<issue_to_address>
**issue:** Storage path from `workload_entity_storage` config is not validated and may be missing.

If `workload_entity_storage` exists but `path` is missing or empty, `storage_path_from_config` becomes `None` and is passed into `WorkloadEntitiesStorageConfig`. Subsequent operations that expect a valid directory (e.g., `copy_directory_content`, ZooKeeper reads) will then fail opaquely. Consider validating `storage_path_from_config` here and either raising a clear error or falling back to `workload_path` when it is not set.
</issue_to_address>

### Comment 4
<location path="ch_backup/logic/workload_entities.py" line_range="121-127" />
<code_context>
+            )
+
+            if entity_name in we_on_clickhouse_list:
+                we_on_clickhouse_statement = (
+                    context.backup_layout.get_local_we_create_statement(entity_name)
+                )
+                if we_on_clickhouse_statement != statement:
+                    context.ch_ctl.drop_workload_entity(entity_name)
</code_context>
<issue_to_address>
**suggestion:** Handling of a missing local workload entity statement relies on implicit `None != statement` comparison.

If `get_local_we_create_statement` returns `None` (e.g., missing file), this condition treats it as a mismatch and always drops/recreates the entity. If that behavior is desired, consider handling the `None` case explicitly (e.g., log a specific message, then drop/restore) so the intent and expectations around missing local files are clearer than relying on `None != statement`.

```suggestion
            if entity_name in we_on_clickhouse_list:
                we_on_clickhouse_statement = (
                    context.backup_layout.get_local_we_create_statement(entity_name)
                )
                if we_on_clickhouse_statement is None:
                    logging.warning(
                        "Local workload entity definition for %s is missing; "
                        "dropping and restoring %s from backup",
                        entity_name,
                        entity_name,
                    )
                    context.ch_ctl.drop_workload_entity(entity_name)
                    context.ch_ctl.restore_workload_entity(statement)
                elif we_on_clickhouse_statement != statement:
                    logging.info(
                        "Local workload entity definition for %s differs from backup; "
                        "recreating entity from backup definition",
                        entity_name,
                    )
                    context.ch_ctl.drop_workload_entity(entity_name)
                    context.ch_ctl.restore_workload_entity(statement)
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread ch_backup/backup/layout.py
Comment on lines +1006 to +1008
try:
self._ch_client.query(DROP_WORKLOAD_SQL.format(entity_name=escape(entity_name)))
except Exception:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Catching a broad Exception when dropping workload entities may hide real errors.

Because any DROP WORKLOAD failure is treated as “must be a RESOURCE”, unrelated errors (permissions, syntax, connection issues, etc.) get silently misclassified and retried. If ClickHouse provides a specific code or message for “WORKLOAD not found”, please check for that explicitly before falling back to DROP RESOURCE, and re-raise all other errors.

Comment on lines +233 to +234
storage_path_from_config = we_config.get("path")
encryption_key_hex_from_config = we_config.get("key_hex")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: Storage path from workload_entity_storage config is not validated and may be missing.

If workload_entity_storage exists but path is missing or empty, storage_path_from_config becomes None and is passed into WorkloadEntitiesStorageConfig. Subsequent operations that expect a valid directory (e.g., copy_directory_content, ZooKeeper reads) will then fail opaquely. Consider validating storage_path_from_config here and either raising a clear error or falling back to workload_path when it is not set.

Comment on lines +121 to +127
if entity_name in we_on_clickhouse_list:
we_on_clickhouse_statement = (
context.backup_layout.get_local_we_create_statement(entity_name)
)
if we_on_clickhouse_statement != statement:
context.ch_ctl.drop_workload_entity(entity_name)
context.ch_ctl.restore_workload_entity(statement)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Handling of a missing local workload entity statement relies on implicit None != statement comparison.

If get_local_we_create_statement returns None (e.g., missing file), this condition treats it as a mismatch and always drops/recreates the entity. If that behavior is desired, consider handling the None case explicitly (e.g., log a specific message, then drop/restore) so the intent and expectations around missing local files are clearer than relying on None != statement.

Suggested change
if entity_name in we_on_clickhouse_list:
we_on_clickhouse_statement = (
context.backup_layout.get_local_we_create_statement(entity_name)
)
if we_on_clickhouse_statement != statement:
context.ch_ctl.drop_workload_entity(entity_name)
context.ch_ctl.restore_workload_entity(statement)
if entity_name in we_on_clickhouse_list:
we_on_clickhouse_statement = (
context.backup_layout.get_local_we_create_statement(entity_name)
)
if we_on_clickhouse_statement is None:
logging.warning(
"Local workload entity definition for %s is missing; "
"dropping and restoring %s from backup",
entity_name,
entity_name,
)
context.ch_ctl.drop_workload_entity(entity_name)
context.ch_ctl.restore_workload_entity(statement)
elif we_on_clickhouse_statement != statement:
logging.info(
"Local workload entity definition for %s differs from backup; "
"recreating entity from backup definition",
entity_name,
)
context.ch_ctl.drop_workload_entity(entity_name)
context.ch_ctl.restore_workload_entity(statement)

@techkuz techkuz marked this pull request as draft March 24, 2026 08:48
@Alex-Burmak Alex-Burmak requested a review from aalexfvk May 20, 2026 08:30
remote_path = _named_collections_data_path(backup_meta.path, filename)
return self._storage_loader.download_data(remote_path, encryption=True)

def upload_workload_entity_ddl_from_file(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's move this function above next to the other upload_ functions

Comment thread ch_backup/backup/layout.py
msg = f"Failed to create async upload of {remote_path}"
raise StorageError(msg) from e

def get_local_we_create_statement(self, entity_name: str) -> Optional[str]:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we is misleading. Lets use workload_entity

"""
try:
self._ch_client.query(DROP_WORKLOAD_SQL.format(entity_name=escape(entity_name)))
except Exception:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exception is too broad here.

Consider keeping entities (workload and resources) separate, or keeping the type together with each entity.

)
if we_on_clickhouse_statement != statement:
context.ch_ctl.drop_workload_entity(entity_name)
context.ch_ctl.restore_workload_entity(statement)
Copy link
Copy Markdown
Contributor

@aalexfvk aalexfvk May 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А workload can reference some resource or another workload through the parent field, forming a hierarchy.

If you restore objects in an arbitrary order, a command like CREATE WORKLOAD child PARENT parent will fail if the parent has not been created yet.

Named collections do not have dependencies on each other, so this problem does not occur with them.

In short resources must be created before workloads, and workloads must be created in topological order (with parents before their children).

@aalexfvk
Copy link
Copy Markdown
Contributor

Pls, resolve the Sourcery comments (either agree and fix or explain and deny as appropriate).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants