diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt index 51a995b..01fbf90 100644 --- a/RELEASE_NOTES.txt +++ b/RELEASE_NOTES.txt @@ -3,10 +3,12 @@ NARRATIVE METHOD STORE OVERVIEW The Narrative Method Store provides an API to dynamically access the available narrative method/app/type specifications and documentation. -VERSION: 0.3.12 (Released TBD) +VERSION: 0.3.12 (Released 10/28/2024) ------------------------------------ UPDATED FEATURES: +- The MongoDB clients have been updated to the most recent version. +- Added the ``mongo-retrywrites`` configuration setting in ``deploy.cfg``, defaulting to ``false``. - Added the `exact_match_on` field to the dynamic dropdown options. - Changed the build system from Make / Ant to Gradle. diff --git a/deploy.cfg b/deploy.cfg index 490d1b4..b9dd01d 100644 --- a/deploy.cfg +++ b/deploy.cfg @@ -58,6 +58,10 @@ method-spec-admin-users = kbaseadmin,kbaseadmin2 endpoint-host=https://ci.kbase.us endpoint-base=/services +# Whether to enable ('true') the MongoDB retryWrites parameter or not (anything other than 'true'). +# See https://www.mongodb.com/docs/manual/core/retryable-writes/ +method-spec-mongo-retrywrites=false + # Default tag used when tag is not specified in Narrative requests. # It should be changed into 'release' in production deployment. method-spec-default-tag = dev diff --git a/deployment/conf/.templates/deployment.cfg.templ b/deployment/conf/.templates/deployment.cfg.templ index ee28e18..dc74db5 100644 --- a/deployment/conf/.templates/deployment.cfg.templ +++ b/deployment/conf/.templates/deployment.cfg.templ @@ -35,6 +35,7 @@ method-spec-mongo-host = {{ default .Env.method_spec_mongo_host "localhost:27017 method-spec-mongo-dbname = {{ default .Env.method_spec_mongo_dbname "method_store_repo_db" }} method-spec-mongo-user = {{ default .Env.method_spec_mongo_user "" }} method-spec-mongo-password = {{ default .Env.method_spec_mongo_password "" }} +method-spec-mongo-retrywrites={{ default .Env.method_spec_mongo_retrywrites "false" }} method-spec-admin-users = {{ default .Env.method_spec_admin_users "kbaseadmin,kbaseadmin2" }} endpoint-host={{ default .Env.endpoint_host "https://ci.kbase.us" }} endpoint-base={{ default .Env.endpoint_base "/services" }} diff --git a/src/main/java/us/kbase/narrativemethodstore/NarrativeMethodStoreServer.java b/src/main/java/us/kbase/narrativemethodstore/NarrativeMethodStoreServer.java index ebd34d2..b2c0dc5 100644 --- a/src/main/java/us/kbase/narrativemethodstore/NarrativeMethodStoreServer.java +++ b/src/main/java/us/kbase/narrativemethodstore/NarrativeMethodStoreServer.java @@ -54,6 +54,7 @@ public class NarrativeMethodStoreServer extends JsonServerServlet { public static final String CFG_PROP_MONGO_USER = "method-spec-mongo-user"; public static final String CFG_PROP_MONGO_PASSWORD = "method-spec-mongo-password"; public static final String CFG_PROP_MONGO_READONLY = "method-spec-mongo-readonly"; + public static final String CFG_PROP_MONGO_RETRY_WRITES = "method-spec-mongo-retrywrites"; public static final String CFG_PROP_ADMIN_USERS = "method-spec-admin-users"; public static final String CFG_PROP_ENDPOINT_BASE = "endpoint-base"; public static final String CFG_PROP_ENDPOINT_HOST = "endpoint-host"; @@ -190,6 +191,10 @@ public static synchronized LocalGitDB getLocalGitDB() throws Exception { String dbPwd = nullIfWhitespace(config().get(CFG_PROP_MONGO_PASSWORD)); System.out.println(NarrativeMethodStoreServer.class.getName() + ": " + CFG_PROP_MONGO_USER +" = " + (dbUser == null ? "" : dbUser)); System.out.println(NarrativeMethodStoreServer.class.getName() + ": " + CFG_PROP_MONGO_PASSWORD +" = " + (dbPwd == null ? "" : "[*****]")); + + final boolean retryWrites = config().get(CFG_PROP_MONGO_RETRY_WRITES).equals("true"); + System.out.println(NarrativeMethodStoreServer.class.getName() + ": " + CFG_PROP_MONGO_RETRY_WRITES +" = " + retryWrites); + String mongoReadOnlyText = config().get(CFG_PROP_MONGO_READONLY); boolean mongoRO = mongoReadOnlyText != null && (mongoReadOnlyText.equals("1") || mongoReadOnlyText.equals("true") || mongoReadOnlyText.equals("y") || mongoReadOnlyText.equals("yes")); @@ -213,7 +218,7 @@ public static synchronized LocalGitDB getLocalGitDB() throws Exception { System.out.println(NarrativeMethodStoreServer.class.getName() + ": " + CFG_PROP_AUTH_INSECURE +" = " + (authAllowInsecure == null ? " ('false' will be used)" : authAllowInsecure)); localGitDB = new LocalGitDB(new URL(getGitRepo()), getGitBranch(), new File(getGitLocalDir()), getGitRefreshRate(), getCacheSize(), - new MongoDynamicRepoDB(getMongoHost(), getMongoDbname(), dbUser, dbPwd, adminUsers, mongoRO), + new MongoDynamicRepoDB(getMongoHost(), getMongoDbname(), dbUser, dbPwd, adminUsers, mongoRO, retryWrites), new File(getTempDir()), new ServiceUrlTemplateEvaluater(endpointHost, endpointBase), RepoTag.valueOf(defaultTag)); } diff --git a/src/main/java/us/kbase/narrativemethodstore/db/mongo/MongoDynamicRepoDB.java b/src/main/java/us/kbase/narrativemethodstore/db/mongo/MongoDynamicRepoDB.java index a484159..328c6a8 100644 --- a/src/main/java/us/kbase/narrativemethodstore/db/mongo/MongoDynamicRepoDB.java +++ b/src/main/java/us/kbase/narrativemethodstore/db/mongo/MongoDynamicRepoDB.java @@ -77,11 +77,12 @@ public MongoDynamicRepoDB( final String dbUser, final String dbPwd, final List globalAdminUserIds, - final boolean isReadOnly) + final boolean isReadOnly, + final boolean retryWrites) throws NarrativeMethodStoreException { this.isReadOnly = isReadOnly; try { - db = getDB(host, database, dbUser, dbPwd); + db = getDB(host, database, dbUser, dbPwd, retryWrites); if (!isReadOnly) ensureIndeces(); globalAdmins = new HashSet(globalAdminUserIds); @@ -90,9 +91,11 @@ public MongoDynamicRepoDB( } } - private MongoDatabase getDB(final String host, final String db, final String user, final String pwd) { - final MongoClientSettings.Builder mongoBuilder = MongoClientSettings.builder().applyToClusterSettings( - builder -> builder.hosts(Arrays.asList(new ServerAddress(host)))); + private MongoDatabase getDB(final String host, final String db, final String user, + final String pwd, final boolean retryWrites) { + final MongoClientSettings.Builder mongoBuilder = MongoClientSettings.builder() + .retryWrites(retryWrites) + .applyToClusterSettings(builder -> builder.hosts(Arrays.asList(new ServerAddress(host)))); final MongoClient cli; if (user != null) { final MongoCredential creds = MongoCredential.createCredential(user, db, pwd.toCharArray()); diff --git a/src/test/java/us/kbase/test/narrativemethodstore/FullServerTest.java b/src/test/java/us/kbase/test/narrativemethodstore/FullServerTest.java index 9a8a9cf..515436e 100644 --- a/src/test/java/us/kbase/test/narrativemethodstore/FullServerTest.java +++ b/src/test/java/us/kbase/test/narrativemethodstore/FullServerTest.java @@ -1472,6 +1472,7 @@ public void debug(String arg0) {} ws.add("method-spec-temp-dir", dbHelper.getWorkDir()); ws.add("method-spec-mongo-host", "localhost:" + dbHelper.getMongoPort()); ws.add("method-spec-mongo-dbname", dbName); + ws.add("method-spec-mongo-retrywrites", "false"); ws.add("method-spec-admin-users", admin1 + "," + admin2); ws.add("endpoint-host", "https://ci.kbase.us"); ws.add("endpoint-base", "/services"); diff --git a/src/test/java/us/kbase/test/narrativemethodstore/db/mongo/MongoDynamicRepoDB2Test.java b/src/test/java/us/kbase/test/narrativemethodstore/db/mongo/MongoDynamicRepoDB2Test.java index dbdc257..3ba67e9 100644 --- a/src/test/java/us/kbase/test/narrativemethodstore/db/mongo/MongoDynamicRepoDB2Test.java +++ b/src/test/java/us/kbase/test/narrativemethodstore/db/mongo/MongoDynamicRepoDB2Test.java @@ -304,6 +304,7 @@ private MongoDynamicRepoDB getDB(final List admins) null, null, admins, + false, false); } diff --git a/src/test/java/us/kbase/test/narrativemethodstore/db/mongo/MongoDynamicRepoDBTest.java b/src/test/java/us/kbase/test/narrativemethodstore/db/mongo/MongoDynamicRepoDBTest.java index 1a23af5..57c2649 100644 --- a/src/test/java/us/kbase/test/narrativemethodstore/db/mongo/MongoDynamicRepoDBTest.java +++ b/src/test/java/us/kbase/test/narrativemethodstore/db/mongo/MongoDynamicRepoDBTest.java @@ -79,7 +79,7 @@ private void testRepo(boolean localFiles) throws Exception { String host = "localhost:" + dbHelper.getMongoPort(); MongoDynamicRepoDB db = new MongoDynamicRepoDB(host, dbName, null, null, - Arrays.asList(globalAdmin), false); + Arrays.asList(globalAdmin), false, false); Assert.assertEquals(0, db.listRepoModuleNames().size()); RepoProvider pvd = localFiles ? new FileRepoProvider(new File(localPath)) : new GitHubRepoProvider(new URL(gitUrl), null, dbHelper.getWorkDir()); @@ -209,7 +209,7 @@ public void testPy() throws Exception { String globalAdmin = "admin"; String host = "localhost:" + dbHelper.getMongoPort(); MongoDynamicRepoDB db = new MongoDynamicRepoDB(host, dbName, null, null, - Arrays.asList(globalAdmin), false); + Arrays.asList(globalAdmin), false, false); Assert.assertEquals(0, db.listRepoModuleNames().size()); RepoProvider pvd = new FileRepoProvider(repoDir); db.registerRepo(userId, pvd);