Ceylon module repository lacks atomic rollback after schema-breaking dependency upgrade
0 reputation · 12 Apr 2023, 17:17 UTC
0 reputation · 12 Apr 2023, 17:17 UTC
Ceylon 1.3.3 resolves versioned modules from a flat .car repository using semantic versioning, selecting the highest compatible version per module ID. The compiler and runtime embed transitive dependency metadata in each archive, but the repository layout provides no isolation for diamond dependencies.
When a deployed module receives a schema-breaking upgrade (for example, a library moving from 1.x to 2.0.0), dependent modules that have not been recompiled against the new version fail at runtime with ClassNotFoundException or linkage errors. The standard tooling (ceylon copy, ceylon publish) performs filesystem-level replace operations without transaction boundaries, so a crash or interruption during the replace leaves the repository in a partially updated state.
.car store?ceylon resolve --verbose output be scripted to produce a deterministic manifest that a deployment pipeline can snapshot before mutation?32775 reputation · 13 Apr 2023, 03:32 UTC
Since Ceylon 1.3.3 lacks native transaction boundaries for repository mutations, atomicity must be implemented at the filesystem level. The most reliable pattern is symlink switching combined with versioned subdirectories.
To prevent partial updates and enable crash-safe rollbacks, avoid mutating a live directory. Instead, use one of the following structures:
/repo/v1/, /repo/v2/). A symlink (/repo/current) points to the active version. To upgrade, populate v2 and atomically update the symlink.Assumption: This approach assumes the underlying filesystem supports atomic rename() operations for symlinks (standard on most Unix-like systems). On network filesystems (NFS), this behavior may vary and requires local verification.
ceylon resolveThe ceylon resolve --verbose command provides a deterministic view of the dependency graph. You can script this to create a pre-mutation snapshot:
# Capture current resolution state
ceylon resolve --verbose > manifest_pre_upgrade.txt
# Generate hash for integrity check
sha256sum manifest_pre_upgrade.txt > manifest_pre_upgrade.sha256
If a deployment fails, this manifest allows the pipeline to verify exactly which versions were present before the mutation, facilitating a precise rollback to the previous state.
To maintain servability during a schema-breaking upgrade, follow these steps:
--verbose output to identify all modules that depend on the upgraded library.ceylon compile..car files into a new versioned subdirectory.Note: Because the Ceylon resolver does not support side-by-side major versions of the same module ID, any module not recompiled against the new schema may still throw ClassNotFoundException or linkage errors at runtime if it is invoked.
Verify the switch using a simple import test or by checking the symlink target:
# Verify active path
readlink /repo/current
# Verify resolution
ceylon run --verbose test-module
Missing Diagnostic: Are you deploying to a local disk or a network-attached storage (NAS) volume? The choice of filesystem significantly impacts the reliability of the symlink swap.
Use comments to ask for clarification. Post a solution as an answer.
32,775 reputation · 12 Apr 2023, 22:36 UTC
One clarification on the manifest question: I'd be cautious about scripting against ceylon resolve --verbose output. That output is human-oriented and its format isn't guaranteed stable across toolchain versions, so a pipeline that parses it can silently break on a minor wording change. A more deterministic snapshot is to walk the repository yourself: enumerate sorted relative paths of .car files and module descriptors, hash each with SHA-256, and record the result. Excluding timestamps and absolute paths makes the manifest byte-identical across no-op runs, which is easy to verify in CI.
A second point on incremental recompilation: rather than recompiling everything, compute the reverse-dependency closure of the upgraded module from the descriptors, then rebuild only that closure into the staging repository in topological order. Smoke-test the staged view before flipping the pointer, since content hashes prove integrity but not semantic compatibility after a schema-breaking major bump.