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

CHE-2435: Add component for clean up workspace folder after remove workspace. #2544

Merged
merged 1 commit into from
Oct 18, 2016

Conversation

AndrienkoAleksandr
Copy link
Contributor

@AndrienkoAleksandr AndrienkoAleksandr commented Sep 22, 2016

What does this PR do?

Add component for clean up workspace folder after remove workspace.

What issues does this PR fix or reference?

#2435

PR type

  • Major change = changes existing features or docs

Minor change checklist

  • API updated
  • Tests provided / updated
  • Tests passed

Major change checklist

  • API updated
  • Documentation provided (include here or link to docs)
  • Tests provided / updated
  • Tests passed

@garagatyi review please.

Signed-off-by: Aleksandr Andrienko [email protected]

*
* @author Alexander Andrienko
*/
public interface WorkspaceProjectStorageCleaner {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WorkspaceFileStorageCleaner or WorkspaceFSStorageCleaner looks somehow better for me. WDYT?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, it's make sense. I'll renamed it soon. Thank you.

@codenvy-ci
Copy link

* @throws TimeoutException
* if process gets more time then defined by {@code timeout}
*/
public static Process execute(String[] commandLine, int timeout, TimeUnit timeUnit, LineConsumer outputConsumer)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If process is ended/killed by the end of execution of this method what for it returns process object?

Copy link
Contributor Author

@AndrienkoAleksandr AndrienkoAleksandr Sep 27, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

throws InterruptedException or IOExeption.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see that it is needed to process return code

Copy link

@garagatyi garagatyi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall OK, but needs some fixes

ProcessBuilder pb = new ProcessBuilder(commandLine).redirectErrorStream(true);

// process will be stopped after timeout
Watchdog watcher = new Watchdog(timeout, timeUnit);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use name for watchdog thread - it will help understand thread dump in case of troubles with the server.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class is utility.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

// consume logs until process ends
process(process, outputConsumer);

process.waitFor();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use timeout here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK

process.waitFor();

if (isTimeoutExceeded.get()) {
throw new TimeoutException();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This exception would be clearer if it had a message on what has happened.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class is utility.

@@ -326,6 +329,9 @@ public void removeWorkspace(String workspaceId) throws ConflictException, Server
if (runtimes.hasRuntime(workspaceId)) {
throw new ConflictException("The workspace '" + workspaceId + "' is currently running and cannot be removed.");
}

workspaceProjectStorageCleaner.remove(workspaceId);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it is clearer then method name clear looks more natural for me than remove

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@Override
public void remove(String workspaceId) {
try {
File workspaceStorage = new File(workspaceFolderPathProvider.getPath(workspaceId));
Copy link

@garagatyi garagatyi Sep 27, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you covered the case when workspace are sharing single folder as a storage of projects?

Copy link
Contributor Author

@AndrienkoAleksandr AndrienkoAleksandr Sep 27, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I''ll look at this case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@garagatyi
Copy link

@evoevodin Please take a look

@garagatyi
Copy link

QA is needed

@AndrienkoAleksandr AndrienkoAleksandr force-pushed the CHE-2435 branch 4 times, most recently from 512b665 to 6860d92 Compare September 27, 2016 13:45
@codenvy-ci
Copy link

@codenvy-ci
Copy link

@AndrienkoAleksandr AndrienkoAleksandr added status/code-review This issue has a pull request posted for it and is awaiting code review completion by the community. and removed status/code-review This issue has a pull request posted for it and is awaiting code review completion by the community. labels Sep 28, 2016
public interface WorkspaceFSStorageCleaner {

/**
* Removes workspace project folder with all data by {@code workspaceId}. Note: all user's projects will be deleted.
Copy link
Contributor

@voievodin voievodin Sep 29, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the definition it's not clear for me what is workspace project folder? Does the workspace have the only one project?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Docs changed

package org.eclipse.che.api.workspace.server;

/**
* This component removes workspace folder from workspace storage. It's used for "delete workspace" operation
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's used for "delete workspace" operation

If this interface exists for certain needs please document this needs better, as it's not clear what the phrase above means. As far as i understand we need this interface for cleaning file system resources after workspace is removed?

Copy link
Contributor Author

@AndrienkoAleksandr AndrienkoAleksandr Sep 30, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This interface need to realize delete workspace folder with projects after remove workspace, I'll fix doc.

String workspacePath = workspaceFolderPathProvider.getPath(workspaceId);
File workspaceStorage = new File(workspacePath);
if (!workspacePath.equals(hostProjectsFolder) && workspaceStorage.exists()) {
FileCleaner.addFile(workspaceStorage);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure that it's expected behaviour, should it be asynchronous? If yes, do you think it's better to document it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think remove workspace folder can be potentionally long time operation(if workspace contains a lot of files and server computer is busy to done this task quickly), so yes I think it should be asynchronous operation. Thank you, I will document it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Documented in the interface WorkspaceFSStorageCleaner

if (!workspacePath.equals(hostProjectsFolder) && workspaceStorage.exists()) {
FileCleaner.addFile(workspaceStorage);
}
} catch (IOException e) {
Copy link
Contributor

@voievodin voievodin Sep 29, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's better throw the exception from the method, document it, and catch it on callers side. The motivation is that if we need to add another cleaner, that cleaner will have to implement a batch of the same logic, like exception handling and it's processing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that failed clean up workspace folder is reason to cancel delete workspace operation. That why I handle exception here.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But it is still better to handle batch of delete operations on higher level and decide there completion of which operation is optional and which not. +1 to what Eugene said

Copy link
Contributor

@voievodin voievodin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please comment on my comments/questions

// consume logs until process ends
process(process, outputConsumer);

process.waitFor(timeout, timeUnit);
Copy link
Contributor

@voievodin voievodin Sep 29, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if instead of using Watchdog we consume all the logs in separate thread and wait for pocess to end or reach timeout, i mean we can use the value returned from the waitFor method to achive this goal,
e.g.

if (!process.waitFor(timeout, timeUnit)) {
    ProcessUtil.kill(process);
}

@garagatyi, @AndrienkoAleksandr what do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @evoevodin, I think we can do it, but this only another way of implementation, it has not any advantages. And current version of code is already tested, so I don't think that we should spend time to another implementation without good reason.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@evoevodin I think it can be really clean solution in term of code.
WDYT about usage of ComplletableFuture.runAsync in such cases? Without that addition of executor and everything like that would not make it simpler.

@codenvy-ci
Copy link

Build # 574 - FAILED

Please check console output at https://ci.codenvycorp.com/job/che-pullrequests-build/574/ to view the results.

@@ -326,6 +329,9 @@ public void removeWorkspace(String workspaceId) throws ConflictException, Server
if (runtimes.hasRuntime(workspaceId)) {
throw new ConflictException("The workspace '" + workspaceId + "' is currently running and cannot be removed.");
}

workspaceFSStorageCleaner.clear(workspaceId);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please cover in tests

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

final boolean createSnapshot = autoSnapshotAttr == null ? defaultAutoSnapshot : parseBoolean(autoSnapshotAttr);
boolean createSnapshot;
if (workspace.isTemporary()) {
createSnapshot = false;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is very nice that you added that fix but , please, cover it in tests

Copy link
Contributor Author

@AndrienkoAleksandr AndrienkoAleksandr Oct 3, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@codenvy-ci
Copy link

Build # 592 - FAILED

Please check console output at https://ci.codenvycorp.com/job/che-pullrequests-build/592/ to view the results.

@codenvy-ci
Copy link

Build # 602 - FAILED

Please check console output at https://ci.codenvycorp.com/job/che-pullrequests-build/602/ to view the results.

@codenvy-ci
Copy link

Build # 609 - FAILED

Please check console output at https://ci.codenvycorp.com/job/che-pullrequests-build/609/ to view the results.

String workspacePath = workspaceFolderPathProvider.getPathByName(workspace.getConfig().getName());
File workspaceStorage = new File(workspacePath);
if (!workspacePath.equals(hostProjectsFolder) && workspaceStorage.exists()) {
FileCleaner.addFile(workspaceStorage);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it would be better to use not bad alternative: IoUtil.deleteRecursive(workspaceStorage); What do you think @garagatyi @evoevodin ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now class LocalWorkspaceFilesCleaner.java works synchronously so I used IoUtil.deleteRecursive

@codenvy-ci
Copy link

Build # 643 - FAILED

Please check console output at https://ci.codenvycorp.com/job/che-pullrequests-build/643/ to view the results.

Copy link
Contributor

@voievodin voievodin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job, please fix some small remarks

* @throws TimeoutException
* if process gets more time then defined by {@code timeout}
*/
public static Process execute(String[] commandLine, int timeout, TimeUnit timeUnit, LineConsumer outputConsumer)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'd probably rename it to executeAndWait as the behaviour is different from the existing execute method

// consume logs until process ends
process(process, outputConsumer);
} catch (IOException e) {
LOG.error(format("Failed to complete process '%s'.", Joiner.on(" ").join(commandLine)), e);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's change the exception method to something like Failed to complete reading of the process '%s' output due to occurred error

});

if (!process.waitFor(timeout, timeUnit)) {
ProcessUtil.kill(process);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's wrap process kill to ensure that user gets TimeoutException
e.g.

            try {
                ProcessUtil.kill(process);
            } catch (RuntimeException x) {
                LOG.error("An error occurred while killing process '{}'", Joiner.on(" ").join(commandLine));
            }

@Inject
public RemoveWorkspaceListener(EventService eventService, WorkspaceFilesCleaner workspaceFilesCleaner) {
this.workspaceFilesCleaner = workspaceFilesCleaner;
eventService.subscribe(this);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

subscribe on events in @PostConstruct

try {
workspaceFilesCleaner.clear(workspace);
} catch (IOException | ServerException e) {
LOG.error("Failed to delete folder for workspace with id: '{}'. Cause: '{}'", workspace.getId(), e.getMessage());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider a different message, less concrete, let's say it's Failed to remove workspace files

@codenvy-ci
Copy link

Build # 665 - FAILED

Please check console output at https://ci.codenvycorp.com/job/che-pullrequests-build/665/ to view the results.

@AndrienkoAleksandr AndrienkoAleksandr changed the title [WIP]CHE-2435: Add component for clean up workspace folder after remove workspace. CHE-2435: Add component for clean up workspace folder after remove workspace. Oct 12, 2016
@codenvy-ci
Copy link

Build # 695 - FAILED

Please check console output at https://ci.codenvycorp.com/job/che-pullrequests-build/695/ to view the results.

Copy link

@garagatyi garagatyi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

@codenvy-ci
Copy link

Build # 734 - FAILED

Please check console output at https://ci.codenvycorp.com/job/che-pullrequests-build/734/ to view the results.

@bmicklea bmicklea added this to the 5.0.0-M6 milestone Oct 19, 2016
JPinkney pushed a commit to JPinkney/che that referenced this pull request Aug 17, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants