-
Notifications
You must be signed in to change notification settings - Fork 38
fix!: cloud assemblies are not locked #344
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
7c5d44b
to
713f092
Compare
713f092
to
98cdf70
Compare
98cdf70
to
b850061
Compare
b850061
to
be679e7
Compare
be679e7
to
d6a8e98
Compare
d6a8e98
to
d4fe065
Compare
d4fe065
to
f6a9804
Compare
4c937b9
to
2e0f62e
Compare
668e481
to
aebc81d
Compare
We need a prerelease version of a Jest package in order to have `Symbol.asyncDispose` available in Jest worker processes. Apparently these global symbols have to be copied over explicitly when Jest is preparing a test environment. See jestjs/jest#14874 This does not affect "production" consumers as we have a polyfill package that we load when the library is imported, but this polyfill package is not loaded during test execution, which is why we need the jest update.
Since the override of `jest-environment-node` there are typing errors in our custom environment implementations. This doesn't seem to affect the tests, but I'd rather not see type errors when looking at the packages in VS Code.
856fa23
to
d0e4090
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just for my general understanding: why do we convert locks from write to read after synth? (As opposed to just deleting it).
packages/@aws-cdk/toolkit-lib/lib/api/cloud-assembly/private/context-aware-source.ts
Outdated
Show resolved
Hide resolved
packages/@aws-cdk/toolkit-lib/lib/api/cloud-assembly/private/context-aware-source.ts
Outdated
Show resolved
Hide resolved
packages/@aws-cdk/toolkit-lib/lib/api/cloud-assembly/cached-source.ts
Outdated
Show resolved
Hide resolved
* - Release the lock on the Cloud Assembly directory | ||
* - Delete the backing directory, if it is a temporary directory. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably nitpicking, but this sounds more like implementation detail than a contract.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's sort of relevant to know what to expect when you call this method, no? :)
d0e4090
to
ee09772
Compare
Cloud Assemblies are supposed to be read-locked as they are being used, so that concurrent writers into the same directories do not trample on the
cdk.out
directory as we are deploying it.This is being done with the class
RWLock
which represents a read/write lock. A lock is associated to a directory, which can have either at most one writer or multiple readers.This PR is a synthesis of #335 and #339.
Closes aws/aws-cdk#32964, closes #335, closes #339.
Design
Because we need to add the concept of a lock to a Cloud Assembly, and we want that resource to be disposable, we introduce the class
IReadableCloudAssembly
. This interface models both a cloud assembly and a dispose function which releases the lock and optionally cleans up the backing directory of the cloud assembly.Cloud Assembly Sources (
ICloudAssemblySource.produce()
) now returns aIReadableCloudAssembly
with a lock associated. The factory functions start off by acquiring write locks on the backing directory during synthesis, which are converted to read locks after a successful synthesis.ICloudAssemblySource
, and dispose of the producedIReadableCloudAssembly
after use;synth()
now returns aCachedCloudAssembly
. That class implements bothIReadableCloudAssembly
(as in, it is a cloud assembly that is locked and ready to be read), as well asICloudAssemblySource
so that it can be passed into other toolkit functions. TheCachedCloudAssembly.produce()
returns borrowed versions ofIReadableCloudAssembly
with dispose functions that don't do anything: only the top-level dispose actually cleans anything up. This is so that if the result ofsynth()
is passed into (multiple) other toolkit functions, their dispose calls don't accidentally release the lock. This could have been done with reference counting, but is currently being done by giving out a "borrowed" Cloud Assembly which doesn't clean up at all.ExecutionEnvironment
; this is now a disposable object which will hold a lock that either gets cleaned up automatically with the object, or get converted to a reader lock when theExecutionEnvironment
is explicitly marked as having successfully completed. That same change now allows us to automatically clean up temporary directories if synthesis fails, or when the CloudAssembly in them is disposed of.Supporting changes
Supporting changes in this PR, necessary to make the above work:
StackAssembly
, which is a helper class to query a Cloud Assembly, used to be anICloudAssemblySource
but it no longer is. That functionality isn't used anywhere.CachedCloudAssemblySource
toCachedCloudAssembly
and makesynth()
return this concretely. It makes more sense to think of this class as a Cloud Assembly (that happens to be usable as a source), than the reverse._unlock()
followed by adispose()
from doing something unexpected, and it also shouldn't fail.ILock
=>IReadLock
to contrast it more clearly with anIWriteLock
.IdentityCloudAssemblySource
, since it fills much the same role asCachedCloudAssembly
.ExecutionEnvironment
is now disposable, and its sync constructor has been changed to an async factory function.cx.produce()
directory now have to use anawait using
statement to make sure the read locks are cleaned up, otherwise they get added to the GitHub repo.New tests for new contracts
toolkit.synth()
can be passed to other toolkit methods, but its contents are only disposed when the object is explicitly disposed, not when it's passed to toolkit methods.Breaking change
BREAKING CHANGE: this change changes the return type of
toolkit.synth()
: it no longer returns an arbitrary Assembly Source (by interface), but a specific Assembly, by class, that can also be used as a source. The return type ofICloudAssemblySource.produce()
has been changed toIReadableCloudAssembly
. This will only affect consumers with custom implementations of that interface, the factory function APIs are unchanged.By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license