-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Changeset execution information properties #5598
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
Changeset execution information properties #5598
Conversation
Hey @filipelautert! Hope you have been well! I created this PR in draft because I'd like some help/opinions here. I've got the majority of this working, but can't figure out how to get the correct DEPLOYMENT_ID. It appears that the properties are all replaced in changelog files before a lock is accquired and the update action is actually run. When the update run is started, accquiring the change lock resets the deployment ID (as explained by this comment. So my question is... any thoughts on how I could achieve getting the deployment ID so it is available to the changes? I'm not hard set on the usage of the properties for this... that is just the first thing that came to mind as that substitution is already built in to Liquibase. Not sure if you or your team mates could think of another mechanism that would be better suited? Thanks! |
18f2410
to
fe84fde
Compare
Hey @jasonlyle88 ! Could you provide an example changelog were you would use the deployment id? But you are right.. we reset the deployment id with each reset. And that's like this because it didn't matter until now as the deployment id is the same for all the operations executed in a single update . OR maybe it would be easier to parse the deployment id parameter after the code comment you mentioned . |
Hey, Here is an example of how I was thinking this could be used <?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ora="http://www.oracle.com/xml/ns/dbchangelog-ext"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.17.xsd"
>
<changeSet
id="example"
author="jlyle"
>
<sql endDelimiter="/">
begin
-- Do installation stuff
...
exception when others
--ERROR HANDLER
logger.log_error(
p_text => 'Error with liquibase run',
p_additional_info => t_info_tab(
t_info_row('Error Code', sqlcode),
t_info_row('Error Message', sqlerrm),
t_info_row('Deployment ID', '${LIQUIBASE_EXECUTION_DEPLOYMENT_ID}'),
t_info_row('Changelog File', '${LIQUIBASE_EXECUTION_CHANGELOG_FILE}'),
t_info_row('Changeset ID', '${LIQUIBASE_EXECUTION_CHANGESET_ID}'),
t_info_row('Changeset Author', '${LIQUIBASE_EXECUTION_CHANGESET_AUTHOR}')
)
);
end;
/
</sql>
</changeSet>
</databaseChangeLog>
I agree only having a singular deployment ID could be problematic. Technically, 10 liquibase updates could be executed at almost the same time and end up with the same deployment ID (since it is time based). But only the first one to get the lock executes and the deployment ID is recalculated at that time. This would distinguish each update attempt because its deployment ID time is based on when it got the lock, not when it was executed. Basically, I agree that the resets are important. I would be interested in how you think the deployment ID could be parsed after the lock is obtained because that would definitely solve the problem. Are you thinking move all parameter replacements to after the database lock is established? Or somehow just doing it for this one special case? |
I suppose we could have a singular deployment ID that does not get reset if we make it more unique. To that end, I did a quick test with the java UUID: import java.util.UUID;
import java.math.BigInteger;
class UUIDToInt {
// Shows that the UUID theoretically can span anything from 1 digit to 39 digits
public static void main(String[] args) {
UUID uuid;
String uuidString;
BigInteger bi;
String integerString;
int shortestLength = 99999999;
int integerLength;
for (int i = 0; i < 30; i++) {
uuid = UUID.randomUUID();
uuidString = uuid.toString().replaceAll( "-" , "" );
if (i == 0) {
// Test smallest possible number
uuidString="00000000000000000000000000000000";
}
else if (i == 1) {
// Test largest possible number
uuidString="ffffffffffffffffffffffffffffffff";
}
bi = new BigInteger( uuidString , 16 );
integerString = bi.toString() ;
integerLength = integerString.length();
if (i > 1 && integerLength < shortestLength) {
shortestLength = integerLength;
}
System.out.println(integerLength + ": " + integerString);
}
System.out.println("Shortest generated length: " + shortestLength);
}
} This shows that theoretically a generated integer from UUID can be anywhere from 1-39 digits long. Although, practically it will most likely be 36+ digits long from my testing. If it is acceptable to convert the deployment ID to a UUID string (always 36 characters long, 32 without dashes) or a UUID numeric representation (0-39 characters long), that would allow a single deployment ID to be generated and not need to be regenerated ever since it is unique. For reference, the deployment ID column is currently a character column of length 10. |
One difference in the UUID based number approach that should be noted is that if N values are generated, the Nth + 1 value is not guaranteed to be greater than the Nth value. Right now, since the DeploymentID is time based, the next generation is always a greater (assuming that it is generated at a different time, which is guaranteed by the database lock) |
Right, that's the idea! I discussed with some people here and we agreed that if it is possible to move the replacement code inside AbstractUpdateCommandStep it would be great (I'm not sure if it would work). Otherwise keep the parameter replacement where is it, but if it finds LIQUIBASE_EXECUTION_DEPLOYMENT_ID then flag it to be replaced after the last lock is acquired. What do you think? |
I'm absolutely up for either of those items. I haven't dug to much into the |
I tried digging into this... and it requires a lot of knowledge about how everything fits together. I'm a little lost at how I could successfully move the replacement of the properties to Also curious to hear feedback about having a more static deployment ID as I discussed above with the UUID/ numeric version of UUID that does not change with the resets! |
Okay... I realized another facet of this last night. Continuing down this path, the replacement of the deployment ID is being done before a checksum is calculated for a changeset. This means that a changeset using this property will always appear as having changed since the changeset would be different because the deployment ID will be different on every execution. This is obviously not ideal (runOnce changesets with this property will cause errors on every run other than the first run and runOnChange changesets will run every single time). So, it may actually be preferable to replace the deployment ID property (and maybe the other properties I am introducing as well?) later in the process (after the checksums have been calculated and after the lock has been acquired/final deployment ID is generated). Do you agree? Is there a mechanism in place already to do property replacements later on in the update process? |
…er connecting to database. Also have DbUrlConnectionCommandStep cleanup force release database locks
….github:jasonlyle88/liquibase into changeset-execution-information-properties
…ated by AbstractDatabaseConnectionCommandStep class
… this is now happening in the database connection command step which comes before the writer setup command step
…up the DATABASECHANGELOGLOCK table when it wasnt before and Im unsure why...
…tion based on command steps
@filipelautert Okay... sorry for all the pings! But I think I have a viable solution. Instead of moving the replacement code later in the overall command process (I couldn't see a clean way to do this without A LOT of refactoring), I instead moved the lock acquistion code sooner in the overall command process. I did this by altering the I ran the full test suite and had to update a couple existing tests because of the logic moving around, but overall this seems to be a pretty small change in the grand scheme of things. Please take a look and let me know if this is viable or not! I also haven't provided any new tests... want to make sure this process is accepted for trying to write tests (if there are any tests you want me to write...) |
It may be cleaner to add a |
Hey @MalloD12 , I don't have a |
Ahh ok, that file |
So this is still an issue. In the docs for how a developer should get started (https://contribute.liquibase.com/code/get-started/env-setup/) it basically says pull the repo and then run |
Then, I would recommend that you create a separate issue for that and then we can ask the docs team to prioritize it. Thanks, |
@filipelautert As this is ready for review, would you mind removing the |
Signed-off-by: jasonlyle88 <jason.lyle88@gmail.com>
@rberezen Looks like this has been approved for 2 weeks, anything I need to know about as to why it hasn't been merged yet? Just want to make sure I'm not missing anything! |
Sorry for the delay. The changes have been merged. Thank you for your contributions! |
No problem, thank you for everything you all do here! |
This PR is created in response to challenges encountered in the creation development of #5598. The purpose of this PR is to create a deployment ID that does have to be changed/generated multiple times and is available early on in the execution timeline. This will allow the implementation of an execution property as setup in #5598 to be created for the deployment ID. However, the deployment ID was generated later in the process to be a time-based number that was obtained after a database lock was obtained to guarantee uniqueness. This PR aims to change the deployment ID from a time-based number to a UUIDv4 to ensure uniqueness. The UUID (36 characters) does not fit in the existing databasechangelog.deployment_id column, so the column is updated in this PR to be a length of 36 (and is updated for both creation of the table and update of existing tables). For a full discussion of why this came to be, the discussion on #5598 can be referenced. --------- Co-authored-by: Jason Lyle <jason.lyle@oracle.com> Co-authored-by: Daniel Mallorga <dmallorga@liquibase.com>
Impact
Description
Fixes #5578
This PR adds the ability to reference the following properties in changelogs:
LIQUIBASE_EXECUTION_DEPLOYMENT_ID- Removed from this PR and has been moved to Deployment ID enhancements and execution property #5653 due to complications discussed in thread belowAllowing for developers to be able to access the above information (for example logging liquibase install information).
Things to be aware of
I added two directories to the .gitignore file because they were created when I ran mvn clean install when there was no differences between my branch and the master branch. If this is unwanted, I can easily remove the .gitignore entries... but I figured it made sense to add them. Let me know what to do in this regards.
Things to worry about
Additional Context