-
Notifications
You must be signed in to change notification settings - Fork 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
[CDAP-20993] Periodic refresh implementation of source control metadata for SCM sync status #15626
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
/* | ||
* Copyright © 2024 Cask Data, Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not | ||
* use this file except in compliance with the License. You may obtain a copy of | ||
* the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
* License for the specific language governing permissions and limitations under | ||
* the License. | ||
*/ | ||
|
||
package io.cdap.cdap.app.store; | ||
|
||
import io.cdap.cdap.proto.SourceControlMetadataRecord; | ||
import java.util.List; | ||
|
||
/** | ||
* Represents a response containing a list of source control metadata records, next page token and | ||
* last refresh time. | ||
*/ | ||
|
||
public class ListSourceControlMetadataResponse { | ||
|
||
private final List<SourceControlMetadataRecord> apps; | ||
private final String nextPageToken; | ||
private final Long lastRefreshTime; | ||
|
||
/** | ||
* Constructs a ListSourceControlMetadataResponse object. | ||
* | ||
* @param apps The list of source control metadata records. | ||
* @param nextPageToken The token for fetching the next page of results. | ||
* @param lastRefreshTime The timestamp of the last refresh operation. | ||
*/ | ||
public ListSourceControlMetadataResponse(List<SourceControlMetadataRecord> apps, | ||
String nextPageToken, Long lastRefreshTime) { | ||
this.apps = apps; | ||
this.nextPageToken = nextPageToken; | ||
this.lastRefreshTime = lastRefreshTime; | ||
} | ||
|
||
public List<SourceControlMetadataRecord> getApps() { | ||
return apps; | ||
} | ||
|
||
public String getNextPageToken() { | ||
return nextPageToken; | ||
} | ||
|
||
public Long getLastRefreshTime() { | ||
return lastRefreshTime; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
/* | ||
* Copyright © 2024 Cask Data, Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not | ||
* use this file except in compliance with the License. You may obtain a copy of | ||
* the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
* License for the specific language governing permissions and limitations under | ||
* the License. | ||
*/ | ||
|
||
package io.cdap.cdap.app.store; | ||
|
||
import io.cdap.cdap.proto.SourceControlMetadataRecord; | ||
|
||
/** | ||
* Represents a response containing a single source control metadata record and last refresh time. | ||
*/ | ||
public class SingleSourceControlMetadataResponse { | ||
|
||
private final SourceControlMetadataRecord app; | ||
private final Long lastRefreshTime; | ||
|
||
/** | ||
* Constructs a SingleSourceControlMetadataResponse object. | ||
* | ||
* @param app The source control metadata record. | ||
* @param lastRefreshTime The timestamp of the last refresh operation. | ||
*/ | ||
public SingleSourceControlMetadataResponse(SourceControlMetadataRecord app, | ||
Long lastRefreshTime) { | ||
this.app = app; | ||
this.lastRefreshTime = lastRefreshTime; | ||
} | ||
|
||
public SourceControlMetadataRecord getApp() { | ||
return app; | ||
} | ||
|
||
public Long getLastRefreshTime() { | ||
return lastRefreshTime; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,8 +33,10 @@ | |
import io.cdap.cdap.api.security.AccessException; | ||
import io.cdap.cdap.app.runtime.ProgramRuntimeService; | ||
import io.cdap.cdap.app.store.ApplicationFilter; | ||
import io.cdap.cdap.app.store.ListSourceControlMetadataResponse; | ||
import io.cdap.cdap.app.store.ScanApplicationsRequest; | ||
import io.cdap.cdap.app.store.ScanSourceControlMetadataRequest; | ||
import io.cdap.cdap.app.store.SingleSourceControlMetadataResponse; | ||
import io.cdap.cdap.common.ApplicationNotFoundException; | ||
import io.cdap.cdap.common.ArtifactAlreadyExistsException; | ||
import io.cdap.cdap.common.BadRequestException; | ||
|
@@ -129,7 +131,6 @@ | |
* Key in json paginated applications list response. | ||
*/ | ||
public static final String APP_LIST_PAGINATED_KEY = "applications"; | ||
public static final String APP_LIST_PAGINATED_KEY_SHORT = "apps"; | ||
|
||
/** | ||
* Runtime program service for running and managing programs. | ||
|
@@ -319,27 +320,29 @@ | |
@QueryParam("filter") String filter | ||
) throws Exception { | ||
validateNamespace(namespaceId); | ||
|
||
JsonPaginatedListResponder.respond(GSON, responder, APP_LIST_PAGINATED_KEY_SHORT, | ||
jsonListResponder -> { | ||
AtomicReference<SourceControlMetadataRecord> lastRecord = new AtomicReference<>(null); | ||
ScanSourceControlMetadataRequest scanRequest = SourceControlMetadataHelper.getScmStatusScanRequest( | ||
namespaceId, | ||
pageToken, pageSize, sortOrder, sortOn, filter); | ||
boolean pageLimitReached = false; | ||
try { | ||
pageLimitReached = applicationLifecycleService.scanSourceControlMetadata( | ||
scanRequest, batchSize, | ||
scmMetaRecord -> { | ||
jsonListResponder.send(scmMetaRecord); | ||
lastRecord.set(scmMetaRecord); | ||
}); | ||
} catch (IOException e) { | ||
responder.sendString(HttpResponseStatus.INTERNAL_SERVER_ERROR, e.getMessage()); | ||
} | ||
SourceControlMetadataRecord record = lastRecord.get(); | ||
return !pageLimitReached || record == null ? null : record.getName(); | ||
}); | ||
List<SourceControlMetadataRecord> apps = new ArrayList<>(); | ||
AtomicReference<SourceControlMetadataRecord> lastRecord = new AtomicReference<>(null); | ||
ScanSourceControlMetadataRequest scanRequest = SourceControlMetadataHelper.getScmStatusScanRequest( | ||
namespaceId, | ||
pageToken, pageSize, sortOrder, sortOn, filter); | ||
boolean pageLimitReached = false; | ||
try { | ||
pageLimitReached = applicationLifecycleService.scanSourceControlMetadata( | ||
scanRequest, batchSize, | ||
scmMetaRecord -> { | ||
apps.add(scmMetaRecord); | ||
lastRecord.set(scmMetaRecord); | ||
}); | ||
} catch (IOException e) { | ||
responder.sendString(HttpResponseStatus.INTERNAL_SERVER_ERROR, e.getMessage()); | ||
} | ||
SourceControlMetadataRecord record = lastRecord.get(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
String nextPageToken = !pageLimitReached || record == null ? null : | ||
record.getName(); | ||
Long lastRefreshTime = applicationLifecycleService.getLastRefreshTime(namespaceId); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This would execute another SQL in another transaction, which may be inconsistent with what has been returned by the |
||
ListSourceControlMetadataResponse response = new ListSourceControlMetadataResponse(apps, | ||
nextPageToken, lastRefreshTime); | ||
responder.sendJson(HttpResponseStatus.OK, GSON.toJson(response)); | ||
} | ||
|
||
/** | ||
|
@@ -357,10 +360,11 @@ | |
@PathParam("namespace-id") final String namespaceId, | ||
@PathParam("app-id") final String appName) throws Exception { | ||
validateApplicationId(namespaceId, appName); | ||
|
||
responder.sendJson(HttpResponseStatus.OK, | ||
GSON.toJson(applicationLifecycleService.getSourceControlMetadataRecord( | ||
new ApplicationReference(namespaceId, appName)))); | ||
SourceControlMetadataRecord app = applicationLifecycleService.getSourceControlMetadataRecord( | ||
new ApplicationReference(namespaceId, appName)); | ||
Long lastRefreshTime = applicationLifecycleService.getLastRefreshTime(namespaceId); | ||
SingleSourceControlMetadataResponse response = new SingleSourceControlMetadataResponse(app, lastRefreshTime); | ||
responder.sendJson(HttpResponseStatus.OK, GSON.toJson(response)); | ||
} | ||
|
||
private ScanApplicationsRequest getScanRequest(String namespaceId, String artifactVersion, | ||
|
@@ -375,7 +379,7 @@ | |
} | ||
if (nameFilter != null && !nameFilter.isEmpty()) { | ||
if (nameFilterType != null) { | ||
switch (nameFilterType) { | ||
case EQUALS: | ||
builder.setApplicationReference(new ApplicationReference(namespaceId, nameFilter)); | ||
break; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,10 +21,10 @@ | |
import com.google.gson.JsonSyntaxException; | ||
import com.google.inject.Inject; | ||
import io.cdap.cdap.api.feature.FeatureFlagsProvider; | ||
import io.cdap.cdap.app.store.ListSourceControlMetadataResponse; | ||
import io.cdap.cdap.app.store.ScanSourceControlMetadataRequest; | ||
import io.cdap.cdap.common.BadRequestException; | ||
import io.cdap.cdap.common.ForbiddenException; | ||
import io.cdap.cdap.common.NotFoundException; | ||
import io.cdap.cdap.common.conf.CConfiguration; | ||
import io.cdap.cdap.common.conf.Constants; | ||
import io.cdap.cdap.common.conf.Constants.AppFabric; | ||
|
@@ -59,6 +59,8 @@ | |
import io.netty.handler.codec.http.FullHttpRequest; | ||
import io.netty.handler.codec.http.HttpResponseStatus; | ||
import java.io.IOException; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.concurrent.atomic.AtomicReference; | ||
import javax.ws.rs.DELETE; | ||
import javax.ws.rs.GET; | ||
|
@@ -156,29 +158,29 @@ public void listAllApplications(FullHttpRequest request, HttpResponder responder | |
@QueryParam("filter") String filter) throws Exception { | ||
checkSourceControlFeatureFlag(); | ||
validateNamespaceId(namespaceId); | ||
JsonPaginatedListResponder.respond(GSON, responder, APP_LIST_PAGINATED_KEY_SHORT, | ||
jsonListResponder -> { | ||
AtomicReference<SourceControlMetadataRecord> lastRecord = new AtomicReference<>(null); | ||
ScanSourceControlMetadataRequest scanRequest = SourceControlMetadataHelper.getScmStatusScanRequest( | ||
namespaceId, | ||
pageToken, pageSize, sortOrder, sortOn, filter); | ||
boolean pageLimitReached = false; | ||
try { | ||
pageLimitReached = sourceControlService.scanRepoMetadata( | ||
scanRequest, batchSize, | ||
record -> { | ||
jsonListResponder.send(record); | ||
lastRecord.set(record); | ||
}); | ||
} catch (IOException e) { | ||
responder.sendString(HttpResponseStatus.INTERNAL_SERVER_ERROR, e.getMessage()); | ||
} catch (NotFoundException e) { | ||
responder.sendString(HttpResponseStatus.NOT_FOUND, e.getMessage()); | ||
} | ||
SourceControlMetadataRecord record = lastRecord.get(); | ||
return !pageLimitReached || record == null ? null : | ||
record.getName(); | ||
}); | ||
List<SourceControlMetadataRecord> apps = new ArrayList<>(); | ||
AtomicReference<SourceControlMetadataRecord> lastRecord = new AtomicReference<>(null); | ||
ScanSourceControlMetadataRequest scanRequest = SourceControlMetadataHelper.getScmStatusScanRequest( | ||
namespaceId, | ||
pageToken, pageSize, sortOrder, sortOn, filter); | ||
boolean pageLimitReached = false; | ||
try { | ||
pageLimitReached = sourceControlService.scanRepoMetadata( | ||
scanRequest, batchSize, | ||
record -> { | ||
apps.add(record); | ||
lastRecord.set(record); | ||
}); | ||
} catch (IOException e) { | ||
responder.sendString(HttpResponseStatus.INTERNAL_SERVER_ERROR, e.getMessage()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above. Please throw. The old code was wrong too, please don't follow with that pattern. |
||
} | ||
SourceControlMetadataRecord record = lastRecord.get(); | ||
String nextPageToken = !pageLimitReached || record == null ? null : | ||
record.getName(); | ||
Long lastRefreshTime = sourceControlService.getLastRefreshTime(namespaceId); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should be using primitive |
||
ListSourceControlMetadataResponse response = new ListSourceControlMetadataResponse(apps, | ||
samdgupi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
nextPageToken, lastRefreshTime); | ||
responder.sendJson(HttpResponseStatus.OK, GSON.toJson(response)); | ||
} | ||
|
||
/** | ||
|
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.
Please throw exception and let the http exception handler to handle the response. If you send here, you need to return from the catch block, otherwise the flow will continue.