Processing outside the API — cinder — branch stable/2026.2
Branch
stable/2026.2@c117f9cf08b4(29.0.0-1-gc117f9cf0) — repository https://opendev.org/openstack/cinder — analysed on 2026-10-28
Almost every Cinder write operation finishes outside the API: the API answers 202 after writing the database and casting an RPC message. This file lists what the three back-end services do on their own: RPC consumers, timers and startup processing. Vendor drivers' internal polling loops (about 40 FixedIntervalLoopingCalls in cinder/volume/drivers/*, waiting for array jobs) are out of scope.
1. Summary
| Process | Trigger | Type | Purpose | Reads | Writes / emits | Defined at |
|---|---|---|---|---|---|---|
| all services | report_state | timer, every [DEFAULT]/report_interval s (10), first run after one interval | heartbeat | services row | services.report_count += 1, updated_at | cinder/service.py:273-275, cinder/service.py:457-505 |
| all services | periodic_tasks | timer, every [DEFAULT]/periodic_interval s (60), random initial delay up to periodic_fuzzy_delay (60) | run the manager's @periodic_task methods when their own spacing is due | — | — | cinder/service.py:277-284 |
| cinder-scheduler | create_volume, create_snapshot, create_group, create_backup, extend_volume, migrate_volume, retype, manage_existing, manage_existing_snapshot | RPC cast (topic cinder-scheduler) | choose a backend, then forward to it | in-memory backend states, services, volumes | RPC cast to cinder-volume.<backend> or cinder-backup.<host>; volume error on failure | cinder/scheduler/manager.py:200-661 |
| cinder-scheduler | update_service_capabilities | RPC fanout cast from every volume and backup service | keep the capacity/capability cache | message payload | in-memory HostManager state | cinder/scheduler/manager.py:139-172, cinder/scheduler/host_manager.py:569-668 |
| cinder-scheduler | get_pools, validate_host_capacity, work_cleanup | RPC call | pool list for the API; capacity check; dispatch cleanup to services | cache, services, workers | RPC casts do_cleanup | cinder/scheduler/manager.py:431-456, cinder/scheduler/manager.py:577-636 |
| cinder-scheduler | _clean_expired_messages | periodic, every [DEFAULT]/message_reap_interval s (86,400), run immediately | delete expired user messages | messages.expires_at | DELETE messages | cinder/scheduler/manager.py:131-132 |
| cinder-scheduler | _clean_expired_reservation | periodic, every [DEFAULT]/reservation_clean_interval s (default reservation_expire = 86,400), run immediately | roll back abandoned quota reservations | reservations.expire < now | quota_usages.reserved -= delta, reservations deleted | cinder/scheduler/manager.py:136-137, cinder/quota.py:430-440 |
| cinder-volume | about 60 RPC methods (create_volume, delete_volume, attachment_update…) | RPC cast/call (topic cinder-volume.<host>@<backend>) | do the storage work through the driver | volumes, snapshots… | status updates, notifications, user messages | cinder/volume/manager.py:746-5469 |
| cinder-volume | publish_service_capabilities | periodic, every [backend]/backend_stats_polling_interval s (60, min 3); also RPC fanout from the API | refresh the driver's capacity and capabilities and send them to the schedulers | driver get_volume_stats (array query) | fanout update_service_capabilities; notification capacity.pool | cinder/volume/manager.py:2902-2906, cinder/volume/manager.py:2743-2858, cinder/manager.py:212-225 |
| cinder-volume | _thread_info | periodic, every 60 s, run immediately | debug log of the thread count | — | DEBUG log | cinder/volume/manager.py:5471-5473 |
| cinder-volume | init_host | process start | initialise the driver (retry reinit_driver_count times with exponential backoff), re-export in-use volumes, clean resources left by a crash | volumes, snapshots, workers for this service | status corrections, re-exports | cinder/volume/manager.py:484-645, cinder/volume/manager.py:691-724 |
| cinder-backup | create_backup, continue_backup, restore_backup, delete_backup, export_record, import_record, reset_status… | RPC cast/call (topic cinder-backup) | run the backup driver | backups, volumes | backup statuses, objects in the backup store | cinder/backup/manager.py |
| cinder-backup | _setup_backup_driver | FixedIntervalLoopingCall every backup_driver_init_check_interval s (60) until the driver passes check_for_setup_error | initialise the backup driver; until then is_working() is false and no heartbeat is sent | — | is_initialized | cinder/backup/manager.py:161-179 |
| cinder-backup | publish_service_capabilities | periodic, every backup_driver_stats_polling_interval s (60) | announce the backup backend state | — | fanout update_service_capabilities | cinder/backup/manager.py:1252-1263 |
| cinder-backup | _notify_progress | FixedIntervalLoopingCall during a chunked backup, every backup_timer_interval s [inferred option name] | progress of a running backup | bytes done | notification backup.createprogress | cinder/backup/chunkeddriver.py:566 |
| cinder-backup | init_host | process start | clean incomplete operations: backups creating/restoring/deleting and their volumes | backups, volumes | error, previous statuses, temporary resources removed | cinder/backup/manager.py:143-158, cinder/backup/manager.py:186 |
| cinder-volume-usage-audit | command (cron) | external scheduler | emit usage notifications for a period | volumes, snapshots, backups in the period | volume.exists, snapshot.exists, backup.exists, create/delete start/end | cinder/cmd/volume_usage_audit.py |
There is no notification listener, no OVSDB event and no cache polling in Cinder. Its "polling" is the capability reporting from volume services to schedulers and the timer-driven cleanups above.
2. cinder-scheduler
2.1 create_volume (RPC cast)
- Trigger: cast on topic
cinder-scheduler, fromVolumeCastTaskof the API (cinder/volume/flows/api/create_volume.py:785-868). Any scheduler instance may consume it. - Emitter:
cinder-api; alsocinder-volumewhen rescheduling a failed creation. - Purpose: choose the backend and pool that will create the volume.
- Data read: the in-memory state of each live backend and pool (capacity, capabilities, last update), refreshed from
services(cinder/scheduler/host_manager.py:680-700); the volume type's extra specs. - Flow:
- Wait, at most
scheduler_driver_init_wait_times (60) after startup, until every volume service has reported its capabilities (cinder/scheduler/manager.py:113-121,cinder/scheduler/manager.py:174-185). - Run the scheduler flow:
ExtractSchedulerSpecTask, thenScheduleCreateVolumeTask(cinder/scheduler/flows/create_volume.py:36-160). - The filter scheduler applies the filters (default
AvailabilityZoneFilter,CapacityFilter,CapabilitiesFilter,cinder/scheduler/host_manager.py:45-57), then the weighers (defaultCapacityWeigher), and removes backends already tried (RetryFilter, at mostscheduler_max_attempts= 3) (cinder/scheduler/filter_scheduler.py:297-364,cinder/scheduler/filter_scheduler.py:539-568). When the request is bound to a backend (group,snapshot_same_host, clone), only that backend is considered. - Write
volumes.host=host@backend#pooland castcreate_volumeto that backend (cinder/scheduler/filter_scheduler.py:94-121).
- Wait, at most
- Error behaviour:
NoValidBackend→ volumeerror, user messageVOLUME_VOLUME_001_003, notificationscheduler.create_volume(ERROR) (cinder/scheduler/flows/create_volume.py:109-160). Other exceptions also seterrorand are logged. - Concurrency: several schedulers keep independent caches. Each one consumes capacity in its own cache when it places a volume (
consume_from_volume) [inferred], so two schedulers can choose the same nearly full pool; the backend then fails and the volume is rescheduled. - Cost: no SQL per candidate; one
servicesread per request (_update_backend_state_map).
2.2 Capacity filter and weigher
CapacityFilter(cinder/scheduler/filters/capacity_filter.py:32-200):free = free_capacity_gb − total × reserved_percentage/100. For thin provisioning (thin_provisioning_supportand notprovisioning:type=thick), the virtual free capacity istotal × max_over_subscription_ratio − provisioned − reserved, and the request passes only if(provisioned + size) / (total − reserved) ≤ max_over_subscription_ratio. Backends reportinginfinite/unknownpass.CapacityWeigher(cinder/scheduler/weights/capacity.py:93-140): weight = virtual free capacity ×capacity_weight_multiplier(1.0);AllocatedCapacityWeigherandVolumeNumberWeigherare optional (multipliers −1.0).
2.3 Other scheduler RPCs
extend_volume: re-checks the capacity of the volume's own backend (backend_passes_filters) before castingextend_volumeto it; failure → volume back to its previous status, quota rolled back, user message…007…[inferred for the message] (cinder/scheduler/manager.py:457-503).migrate_volume,retype,manage_existing*: find or validate a target backend, then cast to the volume service (cinder/scheduler/manager.py:281-430).create_backup: pick a livecinder-backupin the backup's AZ (get_backup_host), savebackups.host, cast to it; no backup service → backuperror, volume back to its previous status, user messageBACKUP_SCHEDULE_ERROR(cinder/scheduler/manager.py:637-661).work_cleanup: forPOST /workers/cleanup, select the services concerned and castdo_cleanupto each (cinder/scheduler/manager.py:577-636).
3. cinder-volume
3.1 create_volume (RPC cast)
- Trigger: cast from the scheduler to
cinder-volume.<host>@<backend>. - Purpose: create the volume on the array, optionally fill it, and make it
available. - Flow (
cinder/volume/flows/manager/create_volume.py:1354-1413):ExtractVolumeRefTask,OnFailureRescheduleTask(reschedules through the scheduler unless the failure is not reschedulable,cinder/volume/flows/manager/create_volume.py:72-222),ExtractVolumeSpecTask, notificationvolume.create.start.CreateVolumeFromSpecTask: raw (driver.create_volume), from snapshot, clone, from image (download through Glance into the volume, or image-volume cache: clone of a cached volume of the image, lockcinder-<image_id>), from backup (cinder/volume/flows/manager/create_volume.py:384-1300).CreateVolumeOnFinishTask: statusavailable,launched_at, notificationvolume.create.end(cinder/volume/flows/manager/create_volume.py:1303-1349).
- Error behaviour: after the last reschedule, the volume is
error, with a user message (…_005_…for image copies,…_008_012for driver failures). The quota stays consumed until the volume is deleted. - Concurrency and idempotency: the
workersrow created for the volume lets another service of the same cluster finish or clean the job if this one dies (@cleanable,cinder/manager.py:265-330).
3.2 delete_volume (RPC cast, lock cinder-<volume_id>-delete_volume)
Unexport, delete on the array (driver.delete_volume), delete snapshots if cascade, release quotas (volumes, gigabytes, per type), soft-delete the row, notifications volume.delete.start/end (cinder/volume/manager.py:929-1150). A VolumeIsBusy from the driver puts the volume back to available; other errors to error_deleting.
3.3 Attach and detach (RPC calls)
attachment_update(call, fromPOST/PUT /attachments):driver.create_exportanddriver.initialize_connection(connector); storesconnection_infoandconnectorinvolume_attachment, statusattaching(cinder/volume/manager.py:4929-5033).attachment_delete(call):driver.terminate_connectionand, when no attachment is left on the host,remove_export; the volume becomesavailableor staysin-use(cinder/volume/manager.py:5035-5065).- Legacy
attach_volume/detach_volume/initialize_connection/terminate_connectionwork the same way for theos-*actions (cinder/volume/manager.py:1399-2120).
3.4 extend_volume (RPC cast)
driver.extend_volume; on success extend_volume_completion: quota commit, size and status (available or in-use) updated, notification volume.resize.end; then, for each attached instance, Nova POST /os-server-external-events volume-extended (2.51). A failed Nova call only records user message VOLUME_VOLUME_007_009. A driver failure → error_extending, quota rolled back, user message …007_010 (cinder/volume/manager.py:2967-3070, cinder/compute/nova.py:216-227).
3.5 publish_service_capabilities (periodic)
- Trigger: periodic task every
backend_stats_polling_interval(60 s); also a fanout cast from the API'spublish_service_capabilitiesand at startup. - Data read:
driver.get_volume_stats(refresh=True), which queries the array; plusallocated_capacity_gbkept in memory. - Effects: fanout cast
update_service_capabilitiesto every scheduler with the pools' capacities and capabilities (thin_provisioning_support,max_over_subscription_ratio,reserved_percentage,multiattach,QoS_support,replication_enabled,filter_function,goodness_function…), pluscapacity.poolnotifications (cinder/volume/manager.py:2743-2906). - Error behaviour: a driver that is not initialised reports nothing, and the backend disappears from the scheduler's view; the heartbeat stops too (
is_working). - Cost: one array query per backend per minute, one fanout message per backend per minute, received by every scheduler.
3.6 Startup cleanup (init_host)
- Driver initialisation, retried
reinit_driver_counttimes (3) with a2^ns backoff (cinder/volume/manager.py:484-511). - Re-export of
in-usevolumes; failure →error(cinder/volume/manager.py:597-604). - Worker cleanup (
CleanableManager.do_cleanup,cinder/manager.py:265-330): for eachworkersrow of this service, check the resource still has the recorded status, then:downloading→ driver clears the download,uploading→ status back from the attachments,deleting→ resume the deletion,creating/downloading→error(cinder/volume/manager.py:691-724). The same is triggered remotely byPOST /workers/cleanupfor a dead service. - Finally, publish capabilities and start the RPC servers.
4. cinder-backup
4.1 create_backup (RPC cast)
- Trigger: cast from the scheduler to
cinder-backup.<host>. - Flow [inferred, summarised from
cinder/backup/manager.py]: callget_backup_deviceon the volume's service (a temporary snapshot or clone for anin-usevolume), attach it locally with os-brick, stream it to the backup driver (Swift by default,cinder.backup.drivers.swift.SwiftBackupDriver; chunked drivers compress, checksum and upload chunks, withbackup.createprogressnotifications), detach, remove temporary resources, set backupavailableand the volume back to its previous status. - Error behaviour: backup
errorwithfail_reason, volume back to its previous status, user messages…013_017–…013_023.
4.2 Restore and delete
restore_backup writes into the target volume (restoring-backup → available, or error_restoring); delete_backup deletes the objects then the row (quota backups, backup_gigabytes released).
5. Commands run by operators
cinder-manage db sync | purge <days> | online_data_migrations,cinder-manage service list | remove,cinder-manage cluster list | remove | rename,cinder-manage volume delete | update_host,cinder-manage quota check | sync,cinder-manage util clean_locks(cinder/cmd/manage.py).cinder-status upgrade check(cinder/cmd/status.py).cinder-volume-usage-audit --start_time … --end_time …for billing (cinder/cmd/volume_usage_audit.py).
Source: reverse-spec-cinder/05-async-processing_stable-2026.2.md. The _rewrite/ and _inventory/ files are not published on the site.