mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-09-20 13:30:46 +02:00
* docs(s3/lifecycle): event-driven redesign
Replaces the synchronous PUT-handler walk with an event-driven worker
model: meta-log reader subscribed to one filer, client-side heap merge
with per-filer-shard MessagePosition cursors, bucket-level bootstrap
with inline delete, blocked-cursor handling for fatal events, durable
retry budget for sustained-transient promotion, retention mode gate
that downgrades reader-driven rules to scan_only when log retention
falls below the rule's event-log horizon.
* docs(s3/lifecycle): record Phase 0 verified assumptions
ReadPersistedLogBuffer payload carries Extended (event marshaled via
SubscribeMetadataResponse → ToProtoEntry). Meta-log files at
topics/.system/log/<date>/<HH-MM>.<filerId> are written without TtlSec
in filer_notify_append.go; retention is unbounded by default and only
shrinks if an operator sets a filer.conf rule with a TTL on the
SystemLogDir prefix. .versions/ filenames are v_<16h-ts><16h-rand>
with old/new (inverted) format distinguished by threshold
0x4000000000000000; getVersionTimestamp / compareVersionIds give
format-agnostic ordering for successor-version discovery.
* feat(s3/lifecycle): rule evaluator and dueAt helper
Evaluate(rule, info, now) returns the EvalResult by object shape:
IsMPUInit -> AbortMultipartUpload, IsDeleteMarker -> ExpireDeleteMarker
when sole survivor, IsLatest -> DeleteObject (Days or Date), non-current
-> DeleteVersion (Days fallback to ModTime when SuccessorModTime is
zero; NewerNoncurrent retention enforced when both are set).
ComputeDueAt mirrors Evaluate's shape and returns the earliest eligible
wall-clock time for the same (rule, info), used by the reader/bootstrap
to decide pending vs inline-delete.
Adds StatusEnabled/Disabled and SmallDelay consts and an IsMPUInit
flag on ObjectInfo so .uploads/<id>/ entries route to AbortMPU without
overloading IsLatest.
No callers; package compiles standalone.
* feat(s3/lifecycle): MinTriggerAge for safety-scan cadence
Returns the smallest non-zero day threshold across the rule's actions.
Used as max(MinTriggerAge, kindFloor) for the per-kind cadence; date,
count-only, and delete-marker-only rules return 0 so callers fall
through to their kind-specific floor.
* feat(s3/lifecycle): EventLogHorizon for retention mode gate
Returns the maximum event age the reader needs for a rule. Days-based
kinds return their day threshold; pure NewerNoncurrent (count) and
ExpiredObjectDeleteMarker return SmallDelay. Date rules return 0 (the
gate skips them). Multi-action rules take the max — strictest horizon
wins.
Drives the Phase 2 mode gate: metaLogRetention < EventLogHorizon(rule)
+ bootstrapLookbackMin -> scan_only with RETENTION_BELOW_HORIZON.
* feat(s3/lifecycle): RuleHash for per-rule state CAS
sha256 over canonicalized form, first 8 bytes. Stable across tag-key
reorder, prefix trailing-slash variation, ID renames, and Status flips
(state continuity is preserved when an operator toggles
Enabled/Disabled). Different action shapes — different days, filter,
or action type — hash differently.
Used by the per-rule state directory layout
/etc/s3/lifecycle/<bucket>/<rule_hash_hex>/ and by the bootstrap
detector's reconcile-on-PUT.
* feat(s3/lifecycle): add s3_lifecycle.proto storage schema
Defines the durable types backing the lifecycle worker:
LifecycleState (per-rule mode + bootstrap_complete + degraded_reason
incl. RETENTION_BELOW_HORIZON / LOST_LOG), PendingItem, EntryIdentity,
BootstrapState, ReaderState (per-filer-shard cursors plus
tail_drained_streams marker), BlockerRecord (rule_hash optional for
pre-evaluation failures), RetryBudgetEntry with the four-shape
StreamKey oneof, and RetryTarget (no action / no expected_identity —
retry replays handler against current state).
No callers; schema only. Wired into the pb Makefile.
* feat(s3/lifecycle): add S3LifecycleParams to TaskParams
Wires lifecycle subroutines into the existing worker dispatch.
Subtype is READ (cluster-singleton meta-log reader), BOOTSTRAP
(per-bucket walker), or DRAIN (per-rule pending). bucket / rule_hash
populated for the latter two; ContinuationHint is an advisory resume
point for kill-resumable BOOTSTRAP / READ.
oneof tag = 14, after the existing ec_balance_params at 13.
* fix(s3/lifecycle): noncurrent delete markers honor NoncurrentDays
A non-current delete marker is just another version per AWS S3 spec
and is eligible under NoncurrentVersionExpirationDays. The
IsDeleteMarker special case is meant only for the *current* delete
marker (sole-survivor ExpiredObjectDeleteMarker action), so guard
that switch arm with IsLatest. Without IsLatest, the bootstrap walker
silently skipped pre-existing non-current delete markers under a
NoncurrentDays rule because ComputeDueAt returned zero.
Mirrors the same fix in evaluate.go so the runtime decision matches.
* fix(s3/lifecycle): preserve prefix trailing slash in RuleHash
"logs" and "logs/" match different object sets under literal
strings.HasPrefix semantics: "logs" matches "logsmore/x", "logs/" does
not. Collapsing them in the hash would let an XML edit silently bind
the new rule to the previous rule's durable state directory, causing
stale bootstrap_complete and stale pending entries against a rule
that now matches a different set.
* fix(s3/lifecycle): add UNSPECIFIED sentinels to enum zero values
Proto3 best practice: enum 0 should be an _UNSPECIFIED sentinel, not
an active value. Persisted state schemas care most: a partially
populated payload (or one written by an older binary that didn't set
the field) would otherwise silently default to a semantically active
value.
- LifecycleState.RuleKind: shifts EXPIRATION_DAYS..EXPIRED_DELETE_MARKER
from 0..5 to 1..6, with RULE_KIND_UNSPECIFIED at 0.
- LifecycleState.RuleMode: shifts EVENT_DRIVEN..PENDING_BOOTSTRAP from
0..4 to 1..5.
- LifecycleState.DegradedReason: replaces NONE=0 with
DEGRADED_REASON_UNSPECIFIED=0 (operators treat both as healthy).
- StreamKind: shifts ORIGINAL..PENDING from 0..3 to 1..4.
- S3LifecycleParams.Subtype: shifts READ..DRAIN from 0..2 to 1..3, so
an unset subtype no longer routes into the cluster-singleton READ task.
No on-disk state has been written yet; renumbering is safe.
* docs(s3/lifecycle): per-action state, not per-rule
A single AWS lifecycle XML <Rule> can declare multiple actions in
parallel (e.g. ExpirationDays=90 + AbortMPU=7 + NoncurrentDays=30).
Each must drive its own delay/horizon/mode/pending stream
independently. Modeling the rule as one compiled entry with one kind
collapses these — picking the smallest delay (7d MPU) means the 90d
expiration cursor advances past objects that aren't yet due, and the
90d action never re-fires.
Restructure storage to per-action: every XML rule expands into N
compiled actions; state lives at <bucket>/<rule_hash>/<action_kind>/.
The intermediate rule_hash directory keeps a rule's actions grouped
for operator listing. Each action has its own state file with its own
mode + bootstrap_complete + degraded_reason; sibling actions of the
same rule can degrade independently.
* fix(s3/lifecycle): per-action proto schema + safety-scan counters
Realigns the durable schema with the per-action storage model and the
safety-scan contract in the design doc.
- Promote LifecycleState.RuleKind to a top-level ActionKind enum and
rename rule_kind -> action_kind. The same enum now also keys
BootstrapKey, PendingKey, and BlockerRecord so per-action streams
under one rule never collapse.
- LifecycleState now keyed by (rule_hash, action_kind). Added
last_safety_scan_ts_ns / next_safety_scan_ts_ns and the four
observability counters the design specifies (evaluated_total,
expired_total, metadata_only_total, error_total). Dropped
last_evaluated_ns, deleted_total, skipped_object_lock_total, and
pending_size — subsumed or out-of-band.
- BlockerRecord.action_kind is OPTIONAL (UNSPECIFIED for
pre-evaluation failures, just like rule_hash).
No on-disk state has been written yet; the renumbering / rename is
free.
* fix(s3/lifecycle): per-action MinTriggerAge / EventLogHorizon helpers
The retention mode gate and safety-scan cadence run on each compiled
action independently. Taking a "min/max across all actions in the
rule" — as the previous helpers did — was wrong: a 90d ExpirationDays
sibling alongside a 7d AbortMPU action would cause the 90d cursor to
advance at 7d (because MinTriggerAge picked the smallest), and the
ExpirationDays action would never re-fire on objects that aged past
the 7d sweep window before reaching 90d.
Both helpers now take an ActionKind and return the threshold for that
specific action only. Returns 0 if the rule does not declare the
requested kind, which makes the gate a no-op and the cadence fall
through to the kind floor.
Also adds RuleActionKinds(rule), the canonical expansion that the
engine uses at compile time to turn one XML rule into N compiled
actions. NewerNoncurrentVersions paired with NoncurrentDays is
subsumed into a single NONCURRENT_DAYS action (AWS-paired
conditions); only when NewerNoncurrent stands alone does it become
NEWER_NONCURRENT.
* fix(s3/lifecycle): length-prefix RuleHash to remove delimiter ambiguity
The previous encoding used "tag=K=V\n" lines, which is ambiguous: a
tag (a=b, c) serializes identically to (a, b=c). A prefix containing
"\nexp_days=99" could likewise forge an action field. Either could
silently bind two semantically different rules to the same per-rule
state directory.
Switch to a length-prefixed canonical form: each scalar is written as
<field-tag-byte> <uvarint-length> <bytes>. Field-tag bytes namespace
each scalar so ("a=b" tag-key) and ("a" tag-key with "=b" leakage)
can't collide. Three regression tests pin the resistance.
* docs(s3/lifecycle): ActionKey is the engine identity, not rule_hash
Finishes the per-action restructure across the engine pseudocode,
bootstrap completion, drain locks, detector paths, policy CAS, and
Phase 2 plan. Every per-action data structure — engine indexes,
target modes, newly-completed sets, bootstrap completion bits, drain
keys, locks, metrics, status — is now keyed by
ActionKey{rule_hash, action_kind}, not by rule_hash alone.
Without this, sibling actions under one XML rule still shared
scheduling state in the engine: originalDelayGroups holding
[]ruleHash means a rule's 7d AbortMPU and 90d ExpirationDays
collapse into one entry, the smaller delay wins for cursor advance,
and the larger sibling never re-fires.
Helper API tightened: EvaluateAction(rule, kind, info, now) and
ComputeDueAt(rule, kind, info) replace the aggregate-rule signatures
so a caller asks one specific action's eligibility against one
entry, never "any action of this rule." Drain task lock includes
action_kind so siblings have independent re-arm timers. Policy CAS
moves from rule_hash to ActionKey membership.
* fix(s3/lifecycle): kind-aware EvaluateAction / ComputeDueAt
Replaces the aggregate-rule signatures with per-action ones:
EvaluateAction(rule, kind, info, now) and ComputeDueAt(rule, kind,
info). The old Evaluate(rule, info, now) could return the verdict of
ANY action declared on the rule, which sat wrong with the per-action
engine indexing (each ActionKey has its own delay group, mode, and
pending stream).
Each helper now decides exactly one (rule, kind) compiled action's
fate against one entry. Asking for a kind the rule doesn't declare,
or asking against the wrong object shape for that kind, returns
ActionNone / zero — never silently routes to a sibling.
Multi-action regression test: a rule with ExpirationDays=90 and
AbortMPU=7 evaluates each kind independently for the same entry; the
7d window has no influence on the 90d eligibility decision.
479 lines
17 KiB
Protocol Buffer
479 lines
17 KiB
Protocol Buffer
syntax = "proto3";
|
|
|
|
package worker_pb;
|
|
|
|
option go_package = "github.com/seaweedfs/seaweedfs/weed/pb/worker_pb";
|
|
|
|
// WorkerService provides bidirectional communication between admin and worker
|
|
service WorkerService {
|
|
// WorkerStream maintains a bidirectional stream for worker communication
|
|
rpc WorkerStream(stream WorkerMessage) returns (stream AdminMessage);
|
|
}
|
|
|
|
// WorkerMessage represents messages from worker to admin
|
|
message WorkerMessage {
|
|
string worker_id = 1;
|
|
int64 timestamp = 2;
|
|
|
|
oneof message {
|
|
WorkerRegistration registration = 3;
|
|
WorkerHeartbeat heartbeat = 4;
|
|
TaskRequest task_request = 5;
|
|
TaskUpdate task_update = 6;
|
|
TaskComplete task_complete = 7;
|
|
WorkerShutdown shutdown = 8;
|
|
TaskLogResponse task_log_response = 9;
|
|
}
|
|
}
|
|
|
|
// AdminMessage represents messages from admin to worker
|
|
message AdminMessage {
|
|
string admin_id = 1;
|
|
int64 timestamp = 2;
|
|
|
|
oneof message {
|
|
RegistrationResponse registration_response = 3;
|
|
HeartbeatResponse heartbeat_response = 4;
|
|
TaskAssignment task_assignment = 5;
|
|
TaskCancellation task_cancellation = 6;
|
|
AdminShutdown admin_shutdown = 7;
|
|
TaskLogRequest task_log_request = 8;
|
|
}
|
|
}
|
|
|
|
// WorkerRegistration message when worker connects
|
|
message WorkerRegistration {
|
|
string worker_id = 1;
|
|
string address = 2;
|
|
repeated string capabilities = 3;
|
|
int32 max_concurrent = 4;
|
|
map<string, string> metadata = 5;
|
|
}
|
|
|
|
// RegistrationResponse confirms worker registration
|
|
message RegistrationResponse {
|
|
bool success = 1;
|
|
string message = 2;
|
|
string assigned_worker_id = 3;
|
|
}
|
|
|
|
// WorkerHeartbeat sent periodically by worker
|
|
message WorkerHeartbeat {
|
|
string worker_id = 1;
|
|
string status = 2;
|
|
int32 current_load = 3;
|
|
int32 max_concurrent = 4;
|
|
repeated string current_task_ids = 5;
|
|
int32 tasks_completed = 6;
|
|
int32 tasks_failed = 7;
|
|
int64 uptime_seconds = 8;
|
|
}
|
|
|
|
// HeartbeatResponse acknowledges heartbeat
|
|
message HeartbeatResponse {
|
|
bool success = 1;
|
|
string message = 2;
|
|
}
|
|
|
|
// TaskRequest from worker asking for new tasks
|
|
message TaskRequest {
|
|
string worker_id = 1;
|
|
repeated string capabilities = 2;
|
|
int32 available_slots = 3;
|
|
}
|
|
|
|
// TaskAssignment from admin to worker
|
|
message TaskAssignment {
|
|
string task_id = 1;
|
|
string task_type = 2;
|
|
TaskParams params = 3;
|
|
int32 priority = 4;
|
|
int64 created_time = 5;
|
|
map<string, string> metadata = 6;
|
|
}
|
|
|
|
// TaskParams contains task-specific parameters with typed variants
|
|
message TaskParams {
|
|
string task_id = 1; // ActiveTopology task ID for lifecycle management
|
|
uint32 volume_id = 2; // Primary volume ID for the task
|
|
string collection = 3; // Collection name
|
|
string data_center = 4; // Primary data center
|
|
string rack = 5; // Primary rack
|
|
uint64 volume_size = 6; // Original volume size in bytes for tracking size changes
|
|
|
|
// Unified source and target arrays for all task types
|
|
repeated TaskSource sources = 7; // Source locations (volume replicas, EC shards, etc.)
|
|
repeated TaskTarget targets = 8; // Target locations (destinations, new replicas, etc.)
|
|
|
|
// Typed task parameters
|
|
oneof task_params {
|
|
VacuumTaskParams vacuum_params = 9;
|
|
ErasureCodingTaskParams erasure_coding_params = 10;
|
|
BalanceTaskParams balance_params = 11;
|
|
ReplicationTaskParams replication_params = 12;
|
|
EcBalanceTaskParams ec_balance_params = 13;
|
|
S3LifecycleParams s3_lifecycle_params = 14;
|
|
}
|
|
}
|
|
|
|
// S3LifecycleParams routes a worker task to one of the three lifecycle
|
|
// subroutines. READ is the cluster-singleton meta-log reader (one task at
|
|
// a time); BOOTSTRAP walks a single bucket; DRAIN drains pending exceptions
|
|
// for a single rule.
|
|
message S3LifecycleParams {
|
|
// Zero is an UNSPECIFIED sentinel: a TaskParams payload whose subtype is
|
|
// unset must not silently route into the cluster-singleton READ task.
|
|
// Callers always populate one of READ / BOOTSTRAP / DRAIN.
|
|
enum Subtype {
|
|
SUBTYPE_UNSPECIFIED = 0;
|
|
READ = 1;
|
|
BOOTSTRAP = 2;
|
|
DRAIN = 3;
|
|
}
|
|
Subtype subtype = 1;
|
|
|
|
// Required for BOOTSTRAP and DRAIN; ignored for READ. rule_hash is
|
|
// optional for BOOTSTRAP (omitting walks all rules for the bucket).
|
|
string bucket = 2;
|
|
bytes rule_hash = 3; // 8 bytes when present
|
|
|
|
bool force = 4; // operator override; bypasses scheduling guards
|
|
int64 batch_time_budget_ns = 5; // 0 = use default
|
|
int32 batch_event_budget = 6; // 0 = use default
|
|
|
|
ContinuationHint continuation = 7; // resume hint for kill-resume tasks
|
|
}
|
|
|
|
// ContinuationHint lets a long-running BOOTSTRAP or READ task hand its
|
|
// resume point to the next scheduled invocation without going through
|
|
// durable state. The durable state files are still authoritative; this
|
|
// is just a scheduling hint to skip an unnecessary fresh start.
|
|
message ContinuationHint {
|
|
string last_scanned_path = 1; // BOOTSTRAP only
|
|
int64 last_position_ns = 2; // READ only (advisory)
|
|
}
|
|
|
|
// VacuumTaskParams for vacuum operations
|
|
message VacuumTaskParams {
|
|
double garbage_threshold = 1; // Minimum garbage ratio to trigger vacuum
|
|
bool force_vacuum = 2; // Force vacuum even if below threshold
|
|
int32 batch_size = 3; // Number of files to process per batch
|
|
string working_dir = 4; // Working directory for temporary files
|
|
bool verify_checksum = 5; // Verify file checksums during vacuum
|
|
}
|
|
|
|
// ErasureCodingTaskParams for EC encoding operations
|
|
message ErasureCodingTaskParams {
|
|
uint64 estimated_shard_size = 1; // Estimated size per shard
|
|
int32 data_shards = 2; // Number of data shards (default: 10)
|
|
int32 parity_shards = 3; // Number of parity shards (default: 4)
|
|
string working_dir = 4; // Working directory for EC processing
|
|
string master_client = 5; // Master server address
|
|
bool cleanup_source = 6; // Whether to cleanup source volume after EC
|
|
}
|
|
|
|
// TaskSource represents a unified source location for any task type
|
|
message TaskSource {
|
|
string node = 1; // Source server address
|
|
uint32 disk_id = 2; // Source disk ID
|
|
string rack = 3; // Source rack for tracking
|
|
string data_center = 4; // Source data center for tracking
|
|
uint32 volume_id = 5; // Volume ID (for volume operations)
|
|
repeated uint32 shard_ids = 6; // Shard IDs (for EC shard operations)
|
|
uint64 estimated_size = 7; // Estimated size to be processed
|
|
}
|
|
|
|
// TaskTarget represents a unified target location for any task type
|
|
message TaskTarget {
|
|
string node = 1; // Target server address
|
|
uint32 disk_id = 2; // Target disk ID
|
|
string rack = 3; // Target rack for tracking
|
|
string data_center = 4; // Target data center for tracking
|
|
uint32 volume_id = 5; // Volume ID (for volume operations)
|
|
repeated uint32 shard_ids = 6; // Shard IDs (for EC shard operations)
|
|
uint64 estimated_size = 7; // Estimated size to be created
|
|
}
|
|
|
|
|
|
|
|
// BalanceMoveSpec describes a single volume move within a batch balance job
|
|
message BalanceMoveSpec {
|
|
uint32 volume_id = 1; // Volume to move
|
|
string source_node = 2; // Source server address (host:port)
|
|
string target_node = 3; // Destination server address (host:port)
|
|
string collection = 4; // Collection name
|
|
uint64 volume_size = 5; // Volume size in bytes (informational)
|
|
}
|
|
|
|
// BalanceTaskParams for volume balancing operations
|
|
message BalanceTaskParams {
|
|
bool force_move = 1; // Force move even with conflicts
|
|
int32 timeout_seconds = 2; // Operation timeout
|
|
int32 max_concurrent_moves = 3; // Max concurrent moves in a batch job (0 = default 5)
|
|
repeated BalanceMoveSpec moves = 4; // Batch: multiple volume moves in one job
|
|
}
|
|
|
|
// ReplicationTaskParams for adding replicas
|
|
message ReplicationTaskParams {
|
|
int32 replica_count = 1; // Target replica count
|
|
bool verify_consistency = 2; // Verify replica consistency after creation
|
|
}
|
|
|
|
// TaskUpdate reports task progress
|
|
message TaskUpdate {
|
|
string task_id = 1;
|
|
string worker_id = 2;
|
|
string status = 3;
|
|
float progress = 4;
|
|
string message = 5;
|
|
map<string, string> metadata = 6;
|
|
}
|
|
|
|
// TaskComplete reports task completion
|
|
message TaskComplete {
|
|
string task_id = 1;
|
|
string worker_id = 2;
|
|
bool success = 3;
|
|
string error_message = 4;
|
|
int64 completion_time = 5;
|
|
map<string, string> result_metadata = 6;
|
|
}
|
|
|
|
// TaskCancellation from admin to cancel a task
|
|
message TaskCancellation {
|
|
string task_id = 1;
|
|
string reason = 2;
|
|
bool force = 3;
|
|
}
|
|
|
|
// WorkerShutdown notifies admin that worker is shutting down
|
|
message WorkerShutdown {
|
|
string worker_id = 1;
|
|
string reason = 2;
|
|
repeated string pending_task_ids = 3;
|
|
}
|
|
|
|
// AdminShutdown notifies worker that admin is shutting down
|
|
message AdminShutdown {
|
|
string reason = 1;
|
|
int32 graceful_shutdown_seconds = 2;
|
|
}
|
|
|
|
// ========== Task Log Messages ==========
|
|
|
|
// TaskLogRequest requests logs for a specific task
|
|
message TaskLogRequest {
|
|
string task_id = 1;
|
|
string worker_id = 2;
|
|
bool include_metadata = 3; // Include task metadata
|
|
int32 max_entries = 4; // Maximum number of log entries (0 = all)
|
|
string log_level = 5; // Filter by log level (INFO, WARNING, ERROR, DEBUG)
|
|
int64 start_time = 6; // Unix timestamp for start time filter
|
|
int64 end_time = 7; // Unix timestamp for end time filter
|
|
}
|
|
|
|
// TaskLogResponse returns task logs and metadata
|
|
message TaskLogResponse {
|
|
string task_id = 1;
|
|
string worker_id = 2;
|
|
bool success = 3;
|
|
string error_message = 4;
|
|
TaskLogMetadata metadata = 5;
|
|
repeated TaskLogEntry log_entries = 6;
|
|
}
|
|
|
|
// TaskLogMetadata contains metadata about task execution
|
|
message TaskLogMetadata {
|
|
string task_id = 1;
|
|
string task_type = 2;
|
|
string worker_id = 3;
|
|
int64 start_time = 4;
|
|
int64 end_time = 5;
|
|
int64 duration_ms = 6;
|
|
string status = 7;
|
|
float progress = 8;
|
|
uint32 volume_id = 9;
|
|
string server = 10;
|
|
string collection = 11;
|
|
string log_file_path = 12;
|
|
int64 created_at = 13;
|
|
map<string, string> custom_data = 14;
|
|
}
|
|
|
|
// TaskLogEntry represents a single log entry
|
|
message TaskLogEntry {
|
|
int64 timestamp = 1;
|
|
string level = 2;
|
|
string message = 3;
|
|
map<string, string> fields = 4;
|
|
float progress = 5;
|
|
string status = 6;
|
|
}
|
|
|
|
// ========== Maintenance Configuration Messages ==========
|
|
|
|
// MaintenanceConfig holds configuration for the maintenance system
|
|
message MaintenanceConfig {
|
|
bool enabled = 1;
|
|
int32 scan_interval_seconds = 2; // How often to scan for maintenance needs
|
|
int32 worker_timeout_seconds = 3; // Worker heartbeat timeout
|
|
int32 task_timeout_seconds = 4; // Individual task timeout
|
|
int32 retry_delay_seconds = 5; // Delay between retries
|
|
int32 max_retries = 6; // Default max retries for tasks
|
|
int32 cleanup_interval_seconds = 7; // How often to clean up old tasks
|
|
int32 task_retention_seconds = 8; // How long to keep completed/failed tasks
|
|
MaintenancePolicy policy = 9;
|
|
}
|
|
|
|
// MaintenancePolicy defines policies for maintenance operations
|
|
message MaintenancePolicy {
|
|
map<string, TaskPolicy> task_policies = 1; // Task type -> policy mapping
|
|
int32 global_max_concurrent = 2; // Overall limit across all task types
|
|
int32 default_repeat_interval_seconds = 3; // Default seconds if task doesn't specify
|
|
int32 default_check_interval_seconds = 4; // Default seconds for periodic checks
|
|
}
|
|
|
|
// TaskPolicy represents configuration for a specific task type
|
|
message TaskPolicy {
|
|
bool enabled = 1;
|
|
int32 max_concurrent = 2;
|
|
int32 repeat_interval_seconds = 3; // Seconds to wait before repeating
|
|
int32 check_interval_seconds = 4; // Seconds between checks
|
|
|
|
// Typed task-specific configuration (replaces generic map)
|
|
oneof task_config {
|
|
VacuumTaskConfig vacuum_config = 5;
|
|
ErasureCodingTaskConfig erasure_coding_config = 6;
|
|
BalanceTaskConfig balance_config = 7;
|
|
ReplicationTaskConfig replication_config = 8;
|
|
EcBalanceTaskConfig ec_balance_config = 9;
|
|
}
|
|
}
|
|
|
|
// Task-specific configuration messages
|
|
|
|
// VacuumTaskConfig contains vacuum-specific configuration
|
|
message VacuumTaskConfig {
|
|
double garbage_threshold = 1; // Minimum garbage ratio to trigger vacuum (0.0-1.0)
|
|
int32 min_volume_age_hours = 2; // Minimum age before vacuum is considered
|
|
int32 min_interval_seconds = 3; // Minimum time between vacuum operations on the same volume
|
|
}
|
|
|
|
// ErasureCodingTaskConfig contains EC-specific configuration
|
|
message ErasureCodingTaskConfig {
|
|
double fullness_ratio = 1; // Minimum fullness ratio to trigger EC (0.0-1.0)
|
|
int32 quiet_for_seconds = 2; // Minimum quiet time before EC
|
|
int32 min_volume_size_mb = 3; // Minimum volume size for EC
|
|
string collection_filter = 4; // Only process volumes from specific collections
|
|
repeated string preferred_tags = 5; // Disk tags to prioritize for EC shard placement
|
|
}
|
|
|
|
// BalanceTaskConfig contains balance-specific configuration
|
|
message BalanceTaskConfig {
|
|
double imbalance_threshold = 1; // Threshold for triggering rebalancing (0.0-1.0)
|
|
int32 min_server_count = 2; // Minimum number of servers required for balancing
|
|
}
|
|
|
|
// ReplicationTaskConfig contains replication-specific configuration
|
|
message ReplicationTaskConfig {
|
|
int32 target_replica_count = 1; // Target number of replicas
|
|
}
|
|
|
|
// EcBalanceTaskParams for EC shard balancing operations
|
|
message EcBalanceTaskParams {
|
|
string disk_type = 1; // Disk type filter (hdd, ssd, "")
|
|
int32 max_parallelization = 2; // Max parallel shard moves within a batch
|
|
int32 timeout_seconds = 3; // Operation timeout per move
|
|
repeated EcShardMoveSpec moves = 4; // Batch: multiple shard moves in one job
|
|
}
|
|
|
|
// EcShardMoveSpec describes a single EC shard move within a batch
|
|
message EcShardMoveSpec {
|
|
uint32 volume_id = 1; // EC volume ID
|
|
uint32 shard_id = 2; // Shard ID (0-13)
|
|
string collection = 3; // Collection name
|
|
string source_node = 4; // Source server address
|
|
uint32 source_disk_id = 5; // Source disk ID
|
|
string target_node = 6; // Target server address
|
|
uint32 target_disk_id = 7; // Target disk ID
|
|
}
|
|
|
|
// EcBalanceTaskConfig contains EC balance-specific configuration
|
|
message EcBalanceTaskConfig {
|
|
double imbalance_threshold = 1; // Threshold for triggering EC shard rebalancing
|
|
int32 min_server_count = 2; // Minimum number of servers required
|
|
string collection_filter = 3; // Collection filter
|
|
string disk_type = 4; // Disk type filter
|
|
repeated string preferred_tags = 5; // Preferred disk tags for placement
|
|
}
|
|
|
|
// ========== Task Persistence Messages ==========
|
|
|
|
// MaintenanceTaskData represents complete task state for persistence
|
|
message MaintenanceTaskData {
|
|
string id = 1;
|
|
string type = 2;
|
|
string priority = 3;
|
|
string status = 4;
|
|
uint32 volume_id = 5;
|
|
string server = 6;
|
|
string collection = 7;
|
|
TaskParams typed_params = 8;
|
|
string reason = 9;
|
|
int64 created_at = 10;
|
|
int64 scheduled_at = 11;
|
|
int64 started_at = 12;
|
|
int64 completed_at = 13;
|
|
string worker_id = 14;
|
|
string error = 15;
|
|
double progress = 16;
|
|
int32 retry_count = 17;
|
|
int32 max_retries = 18;
|
|
|
|
// Enhanced fields for detailed task tracking
|
|
string created_by = 19;
|
|
string creation_context = 20;
|
|
repeated TaskAssignmentRecord assignment_history = 21;
|
|
string detailed_reason = 22;
|
|
map<string, string> tags = 23;
|
|
TaskCreationMetrics creation_metrics = 24;
|
|
}
|
|
|
|
// TaskAssignmentRecord tracks worker assignments for a task
|
|
message TaskAssignmentRecord {
|
|
string worker_id = 1;
|
|
string worker_address = 2;
|
|
int64 assigned_at = 3;
|
|
int64 unassigned_at = 4; // Optional: when worker was unassigned
|
|
string reason = 5; // Reason for assignment/unassignment
|
|
}
|
|
|
|
// TaskCreationMetrics tracks why and how a task was created
|
|
message TaskCreationMetrics {
|
|
string trigger_metric = 1; // Name of metric that triggered creation
|
|
double metric_value = 2; // Value that triggered creation
|
|
double threshold = 3; // Threshold that was exceeded
|
|
VolumeHealthMetrics volume_metrics = 4; // Volume health at creation time
|
|
map<string, string> additional_data = 5; // Additional context data
|
|
}
|
|
|
|
// VolumeHealthMetrics captures volume state at task creation
|
|
message VolumeHealthMetrics {
|
|
uint64 total_size = 1;
|
|
uint64 used_size = 2;
|
|
uint64 garbage_size = 3;
|
|
double garbage_ratio = 4;
|
|
int32 file_count = 5;
|
|
int32 deleted_file_count = 6;
|
|
int64 last_modified = 7;
|
|
int32 replica_count = 8;
|
|
bool is_ec_volume = 9;
|
|
string collection = 10;
|
|
}
|
|
|
|
// TaskStateFile wraps task data with metadata for persistence
|
|
message TaskStateFile {
|
|
MaintenanceTaskData task = 1;
|
|
int64 last_updated = 2;
|
|
string admin_version = 3;
|
|
} |