Skip to content
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

SNOW-1373151: Proactively refresh token to avoid token expiration exception from JDBC #780

Merged
merged 9 commits into from
Jul 16, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 15 additions & 25 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@

<!-- Set our Language Level to Java 8 -->
<properties>
<aircompressor.version>0.27</aircompressor.version>
<bouncycastle.version>1.78.1</bouncycastle.version>
<codehaus.version>1.9.13</codehaus.version>
<commonscodec.version>1.15</commonscodec.version>
Expand All @@ -46,7 +45,7 @@
<commonslang3.version>3.14.0</commonslang3.version>
<commonslogging.version>1.3.1</commonslogging.version>
<commonstext.version>1.11.0</commonstext.version>
<fasterxml.version>2.16.1</fasterxml.version>
<fasterxml.version>2.17.0</fasterxml.version>
<guava.version>32.0.1-jre</guava.version>
<hadoop.version>3.3.6</hadoop.version>
<jacoco.skip.instrument>true</jacoco.skip.instrument>
Expand All @@ -61,13 +60,13 @@
<netty.version>4.1.94.Final</netty.version>
<nimbusds.version>9.37.3</nimbusds.version>
<objenesis.version>3.1</objenesis.version>
<parquet.version>1.13.1</parquet.version>
<parquet.version>1.14.1</parquet.version>
<powermock.version>2.0.9</powermock.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<protobuf.version>3.19.6</protobuf.version>
<shadeBase>net.snowflake.ingest.internal</shadeBase>
<slf4j.version>1.7.36</slf4j.version>
<snappy.version>1.1.10.4</snappy.version>
<snappy.version>1.1.10.5</snappy.version>
<snowjdbc.version>3.16.1</snowjdbc.version>
<yetus.version>0.13.0</yetus.version>
</properties>
Expand Down Expand Up @@ -116,11 +115,6 @@
<artifactId>commons-logging</artifactId>
<version>${commonslogging.version}</version>
</dependency>
<dependency>
<groupId>io.airlift</groupId>
<artifactId>aircompressor</artifactId>
<version>${aircompressor.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-buffer</artifactId>
Expand Down Expand Up @@ -349,13 +343,13 @@
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>1.10.19</version>
<version>1.14.9</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy-agent</artifactId>
<version>1.10.19</version>
<version>1.14.9</version>
<scope>test</scope>
</dependency>
<dependency>
Expand Down Expand Up @@ -420,10 +414,6 @@
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</dependency>
<dependency>
<groupId>io.airlift</groupId>
<artifactId>aircompressor</artifactId>
</dependency>

<!-- https://mvnrepository.com/artifact/io.dropwizard.metrics/metrics-core -->
<dependency>
Expand Down Expand Up @@ -501,7 +491,7 @@
<dependency>
<groupId>com.github.luben</groupId>
<artifactId>zstd-jni</artifactId>
<version>1.5.0-1</version>
<version>1.5.6-2</version>
<scope>runtime</scope>
</dependency>
<dependency>
Expand Down Expand Up @@ -733,11 +723,10 @@
<ignoreNonCompile>true</ignoreNonCompile>
<ignoredDependencies>
<!-- We defined these as direct dependencies (as opposed to just declaring it in dependencyManagement)
to workaround https://issues.apache.org/jira/browse/MNG-7982. Now the dependency analyzer complains that
the dependency is unused, so we ignore it here-->
to workaround https://issues.apache.org/jira/browse/MNG-7982. Now the dependency analyzer complains that
the dependency is unused, so we ignore it here-->
<ignoredDependency>org.apache.commons:commons-compress</ignoredDependency>
<ignoredDependency>org.apache.commons:commons-configuration2</ignoredDependency>
<ignoredDependency>io.airlift:aircompressor</ignoredDependency>
</ignoredDependencies>
</configuration>
</execution>
Expand Down Expand Up @@ -830,9 +819,9 @@
<configuration>
<errorRemedy>failFast</errorRemedy>
<!--
The list of allowed licenses. If you see the build failing due to "There are some forbidden licenses used, please
check your dependencies", verify the conditions of the license and add the reference to it here.
-->
The list of allowed licenses. If you see the build failing due to "There are some forbidden licenses used, please
check your dependencies", verify the conditions of the license and add the reference to it here.
-->
<includedLicenses>
<includedLicense>Apache License 2.0</includedLicense>
<includedLicense>BSD 2-Clause License</includedLicense>
Expand All @@ -841,6 +830,7 @@
<includedLicense>EDL 1.0</includedLicense>
<includedLicense>The Go license</includedLicense>
<includedLicense>Bouncy Castle Licence</includedLicense>
<includedLicense>CDDL + GPLv2 with classpath exception</includedLicense>
</includedLicenses>
<excludedScopes>test,provided,system</excludedScopes>
<failOnBlacklist>true</failOnBlacklist>
Expand Down Expand Up @@ -1144,9 +1134,9 @@
</executions>
</plugin>
<!--
Plugin executes license processing Python script, which copies third party license files into the directory
target/generated-licenses-info/META-INF/third-party-licenses, which is then included in the shaded JAR.
-->
Plugin executes license processing Python script, which copies third party license files into the directory
target/generated-licenses-info/META-INF/third-party-licenses, which is then included in the shaded JAR.
-->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
Expand Down
9 changes: 7 additions & 2 deletions scripts/process_licenses.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
MIT_LICENSE = "The MIT License"
GO_LICENSE = "The Go license"
BOUNCY_CASTLE_LICENSE = "Bouncy Castle Licence <https://www.bouncycastle.org/licence.html>"
CDDL_GPLv2 = "CDDL + GPLv2 with classpath exception"

# The SDK does not need to include licenses of dependencies, which aren't shaded
IGNORED_DEPENDENCIES = {"net.snowflake:snowflake-jdbc", "org.slf4j:slf4j-api"}
Expand Down Expand Up @@ -61,6 +62,7 @@
"org.bouncycastle:bcpkix-jdk18on": BOUNCY_CASTLE_LICENSE,
"org.bouncycastle:bcutil-jdk18on": BOUNCY_CASTLE_LICENSE,
"org.bouncycastle:bcprov-jdk18on": BOUNCY_CASTLE_LICENSE,
"javax.annotation:javax.annotation-api": CDDL_GPLv2
}


Expand Down Expand Up @@ -132,18 +134,21 @@ def main():
dependency_without_license_count += 1
missing_licenses_str += f"{dependency_lookup_key}: {license_name}\n"
else:
raise Exception(f"The dependency {dependency_lookup_key} does not ship a license file, but neither is it not defined in ADDITIONAL_LICENSES_MAP")
raise Exception(
f"The dependency {dependency_lookup_key} does not ship a license file, but neither is it not defined in ADDITIONAL_LICENSES_MAP")

with open(Path(target_dir, "ADDITIONAL_LICENCES"), "w") as additional_licenses_handle:
additional_licenses_handle.write(missing_licenses_str)

if dependency_count < 30:
raise Exception(f"Suspiciously low number of dependency JARs detected in {dependency_jars_path}: {dependency_count}")
raise Exception(
f"Suspiciously low number of dependency JARs detected in {dependency_jars_path}: {dependency_count}")
print("License generation finished")
print(f"\tTotal dependencies: {dependency_count}")
print(f"\tTotal dependencies (with license): {dependency_with_license_count}")
print(f"\tTotal dependencies (without license): {dependency_without_license_count}")
print(f"\tIgnored dependencies: {dependency_ignored_count}")


if __name__ == "__main__":
main()
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Paths;
import java.time.Duration;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
Expand Down Expand Up @@ -47,6 +49,11 @@ class StreamingIngestStage {
private static final long REFRESH_THRESHOLD_IN_MS =
TimeUnit.MILLISECONDS.convert(1, TimeUnit.MINUTES);

// Stage credential refresh interval, currently the token will expire in 1hr for GCS and 2hr for
sfc-gh-psaha marked this conversation as resolved.
Show resolved Hide resolved
// AWS/Azure, so set it a bit smaller than 1hr
private static final Duration refreshDuration = Duration.ofMinutes(58);
private static Instant prevRefresh = Instant.EPOCH;

private static final Logging logger = new Logging(StreamingIngestStage.class);

/**
Expand Down Expand Up @@ -180,6 +187,12 @@ private void putRemote(String fullFilePath, byte[] data, int retryCount)
InputStream inStream = new ByteArrayInputStream(data);

try {
// Proactively refresh the credential if it's going to expire, to avoid the token expiration
// error from JDBC which confuses customer
if (Instant.now().isAfter(prevRefresh.plus(refreshDuration))) {
refreshSnowflakeMetadata();
}

SnowflakeFileTransferAgent.uploadWithoutConnection(
SnowflakeFileTransferConfig.Builder.newInstance()
.setSnowflakeFileTransferMetadata(fileTransferMetadataCopy)
Expand All @@ -194,9 +207,6 @@ private void putRemote(String fullFilePath, byte[] data, int retryCount)
} catch (Exception e) {
if (retryCount == 0) {
// for the first exception, we always perform a metadata refresh.
logger.logInfo(
"Stage metadata need to be refreshed due to upload error: {} on first retry attempt",
e.getMessage());
this.refreshSnowflakeMetadata();
}
if (retryCount >= maxUploadRetries) {
Expand Down Expand Up @@ -281,6 +291,8 @@ synchronized SnowflakeFileTransferMetadataWithAge refreshSnowflakeMetadata(boole
SnowflakeFileTransferAgent.getFileTransferMetadatas(responseNode).get(0),
Optional.of(System.currentTimeMillis()));
}

prevRefresh = Instant.now();
return this.fileTransferMetadataWithAge;
}

Expand Down
Loading