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

[Code] Remove socket.io and use polling message to pull progresses #31398

Merged
merged 3 commits into from
Feb 22, 2019
Merged
Show file tree
Hide file tree
Changes from all 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
4 changes: 0 additions & 4 deletions x-pack/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,6 @@
"@types/redux-actions": "^2.2.1",
"@types/rimraf": "^2.0.2",
"@types/sinon": "^7.0.0",
"@types/socket.io": "^1.4.38",
"@types/socket.io-client": "^1.4.32",
"@types/styled-components": "^3.0.1",
"@types/storybook__addon-actions": "^3.4.1",
"@types/storybook__addon-info": "^3.4.2",
Expand Down Expand Up @@ -304,8 +302,6 @@
"rison-node": "0.3.1",
"rxjs": "^6.2.1",
"semver": "5.1.0",
"socket.io": "^2.1.1",
"socket.io-client": "^2.1.1",
"squel": "^5.12.2",
"stats-lite": "^2.2.0",
"style-it": "2.1.2",
Expand Down
4 changes: 4 additions & 0 deletions x-pack/plugins/code/public/actions/status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ export const loadStatus = createAction<string>('LOAD STATUS');
export const loadStatusSuccess = createAction<any>('LOAD STATUS SUCCESS');
export const loadStatusFailed = createAction<string>('LOAD STATUS FAILED');

export const pollRepoCloneStatus = createAction<any>('POLL CLONE STATUS');
export const pollRepoIndexStatus = createAction<any>('POLL INDEX STATUS');
export const pollRepoDeleteStatus = createAction<any>('POLL DELETE STATUS');

export const loadRepo = createAction<string>('LOAD REPO');
export const loadRepoSuccess = createAction<any>('LOAD REPO SUCCESS');
export const loadRepoFailed = createAction<any>('LOAD REPO FAILED');
Expand Down
4 changes: 0 additions & 4 deletions x-pack/plugins/code/public/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,8 @@ import chrome from 'ui/chrome';
// @ts-ignore
import { uiModules } from 'ui/modules';
import { App } from './components/app';
import { bindSocket } from './socket';
import { store } from './stores';

// Bind the web socket client.
bindSocket(store);

const app = uiModules.get('apps/code');

app.config(($locationProvider: any) => {
Expand Down
3 changes: 2 additions & 1 deletion x-pack/plugins/code/public/components/main/content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { RepoState, RepoStatus, RootState } from '../../reducers';
import {
currentTreeSelector,
hasMoreCommitsSelector,
repoUriSelector,
statusSelector,
treeCommitsSelector,
} from '../../selectors';
Expand Down Expand Up @@ -374,7 +375,7 @@ const mapStateToProps = (state: RootState) => ({
commits: treeCommitsSelector(state),
hasMoreCommits: hasMoreCommitsSelector(state),
loadingCommits: state.file.loadingCommits,
repoStatus: statusSelector(state),
repoStatus: statusSelector(state, repoUriSelector(state)),
repoScope: state.search.searchOptions.repoScope.map(r => r.uri),
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/

import React from 'react';
import { MemoryRouter } from 'react-router';
import { MemoryRouter } from 'react-router-dom';
import renderer from 'react-test-renderer';
import { mockFunction } from '../../utils/test_utils';
import { CodeSymbolTree } from './code_symbol_tree';
Expand Down
11 changes: 10 additions & 1 deletion x-pack/plugins/code/public/sagas/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,13 @@ import {
import { watchFetchBranchesAndCommits, watchFetchRepoTree, watchRepoRouteChange } from './file';
import { watchInstallLanguageServer, watchLoadLanguageServers } from './language_server';
import { watchLoadConfigs, watchSwitchProjectLanguageServer } from './project_config';
import { watchLoadRepoListStatus, watchLoadRepoStatus } from './project_status';
import {
watchLoadRepoListStatus,
watchLoadRepoStatus,
watchRepoCloneStatusPolling,
watchRepoDeleteStatusPolling,
watchRepoIndexStatusPolling,
} from './project_status';
import {
watchAdminRouteChange,
watchDeleteRepo,
Expand Down Expand Up @@ -68,4 +74,7 @@ export function* rootSaga() {
yield fork(watchLoadConfigs);
yield fork(watchLoadRepoListStatus);
yield fork(watchLoadRepoStatus);
yield fork(watchRepoDeleteStatusPolling);
yield fork(watchRepoIndexStatusPolling);
yield fork(watchRepoCloneStatusPolling);
}
216 changes: 203 additions & 13 deletions x-pack/plugins/code/public/sagas/project_status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,38 @@
*/

import { Action } from 'redux-actions';
import { all, call, put, takeEvery } from 'redux-saga/effects';
import { delay } from 'redux-saga';
import { all, call, put, takeEvery, takeLatest } from 'redux-saga/effects';
import { kfetch } from 'ui/kfetch';
import { Repository } from '../../model';
import { fetchReposSuccess } from '../actions';
import { loadRepoSuccess, loadStatusFailed, loadStatusSuccess } from '../actions';

import { RepositoryUtils } from '../../common/repository_utils';
import { Repository, RepositoryUri, WorkerReservedProgress } from '../../model';
import {
deleteRepo,
fetchReposSuccess,
importRepo,
indexRepo,
loadRepoSuccess,
loadStatusFailed,
loadStatusSuccess,
pollRepoCloneStatus,
pollRepoDeleteStatus,
pollRepoIndexStatus,
updateCloneProgress,
updateDeleteProgress,
updateIndexProgress,
} from '../actions';
import { cloneCompletedPattern } from './status';

function fetchStatus(repoUri: string) {
return kfetch({
pathname: `../api/code/repo/status/${repoUri}`,
});
}

function* loadRepoListStatus(action: Action<Repository[]>) {
function* loadRepoListStatus(repos: Repository[]) {
try {
const repositories = action.payload!;
const promises = repositories.map(repo => call(fetchStatus, repo.uri));
const promises = repos.map(repo => call(fetchStatus, repo.uri));
const statuses = yield all(promises);
yield put(
loadStatusSuccess(
Expand All @@ -35,24 +51,198 @@ function* loadRepoListStatus(action: Action<Repository[]>) {
}
}

function* loadRepoStatus(action: Action<any>) {
function* loadRepoStatus(repo: Repository) {
try {
const repository = action.payload!;
const repoStatus = yield call(fetchStatus, repository.uri);
const repoStatus = yield call(fetchStatus, repo.uri);
yield put(
loadStatusSuccess({
[repository.uri]: repoStatus,
[repo.uri]: repoStatus,
})
);
} catch (err) {
yield put(loadStatusFailed(err));
}
}

function* handleRepoStatus(action: Action<any>) {
const repository: Repository = action.payload!;
yield call(loadRepoStatus, repository);
}

function* handleRepoListStatus(action: Action<Repository[]>) {
const repos: Repository[] = action.payload!;
yield call(loadRepoListStatus, repos);
}

function isInProgress(progress: number): boolean {
return progress < WorkerReservedProgress.COMPLETED && progress >= WorkerReservedProgress.INIT;
}

function* handleRepoListStatusLoaded(action: Action<any>) {
const statuses = action.payload;
for (const repoUri of Object.keys(statuses)) {
const status = statuses[repoUri];
if (status.deleteStatus) {
yield put(pollRepoDeleteStatus(repoUri));
} else if (status.indexStatus) {
if (isInProgress(status.indexStatus.progress)) {
yield put(pollRepoIndexStatus(repoUri));
}
} else if (status.gitStatus) {
if (isInProgress(status.gitStatus.progress)) {
yield put(pollRepoCloneStatus(repoUri));
}
}
}
}

// `fetchReposSuccess` is issued by the repository admin page.
export function* watchLoadRepoListStatus() {
yield takeEvery(String(fetchReposSuccess), loadRepoListStatus);
yield takeEvery(String(fetchReposSuccess), handleRepoListStatus);
// After all the status of all the repositoriesin the list has been loaded,
// start polling status only for those still in progress.
yield takeEvery(String(loadStatusSuccess), handleRepoListStatusLoaded);
}

// `loadRepoSuccess` is issued by the main source view page.
export function* watchLoadRepoStatus() {
yield takeEvery(String(loadRepoSuccess), loadRepoStatus);
yield takeLatest(String(loadRepoSuccess), handleRepoStatus);
}

const REPO_STATUS_POLLING_FREQ_MS = 1000;

function createRepoStatusPollingHandler(
parseRepoUri: (_: Action<any>) => RepositoryUri,
handleStatus: any,
pollingActionFunction: any
) {
return function*(a: Action<any>) {
yield call(delay, REPO_STATUS_POLLING_FREQ_MS);

const repoUri = parseRepoUri(a);
let keepPolling = false;
try {
const repoStatus = yield call(fetchStatus, repoUri);
keepPolling = yield handleStatus(repoStatus, repoUri);
} catch (err) {
// Fetch repository status error. Ignore and keep trying.
keepPolling = true;
}

if (keepPolling) {
yield put(pollingActionFunction(repoUri));
}
};
}

const handleRepoCloneStatusPolling = createRepoStatusPollingHandler(
(action: Action<any>) => {
if (action.type === String(importRepo)) {
const repoUrl: string = action.payload;
return RepositoryUtils.buildRepository(repoUrl).uri;
} else if (action.type === String(pollRepoCloneStatus)) {
return action.payload;
}
},
function*(status: any, repoUri: RepositoryUri) {
if (status.gitStatus) {
const { progress, cloneProgress } = status.gitStatus;
yield put(
updateCloneProgress({
progress,
repoUri,
cloneProgress,
})
);
// Keep polling if the progress is not 100% yet.
return isInProgress(progress);
} else {
// Keep polling if the indexStatus has not been persisted yet.
return true;
}
},
pollRepoCloneStatus
);

export function* watchRepoCloneStatusPolling() {
// The repository clone status polling will be triggered by:
// * user click import repository
// * repeating pollRepoCloneStatus action by the poller itself.
yield takeEvery([String(importRepo), String(pollRepoCloneStatus)], handleRepoCloneStatusPolling);
}

const handleRepoIndexStatusPolling = createRepoStatusPollingHandler(
(action: Action<any>) => {
if (action.type === String(indexRepo) || action.type === String(pollRepoIndexStatus)) {
return action.payload;
} else if (action.type === String(updateCloneProgress)) {
return action.payload.repoUri;
}
},
function*(status: any, repoUri: RepositoryUri) {
if (status.indexStatus) {
yield put(
updateIndexProgress({
progress: status.indexStatus.progress,
repoUri,
})
);
// Keep polling if the progress is not 100% yet.
return isInProgress(status.indexStatus.progress);
} else {
// Keep polling if the indexStatus has not been persisted yet.
return true;
}
},
pollRepoIndexStatus
);

export function* watchRepoIndexStatusPolling() {
// The repository index status polling will be triggered by:
// * user click index repository
// * clone is done
// * repeating pollRepoIndexStatus action by the poller itself.
yield takeEvery(
[String(indexRepo), cloneCompletedPattern, String(pollRepoIndexStatus)],
handleRepoIndexStatusPolling
);
}

const handleRepoDeleteStatusPolling = createRepoStatusPollingHandler(
(action: Action<any>) => {
return action.payload;
},
function*(status: any, repoUri: RepositoryUri) {
if (!status.gitStatus && !status.indexStatus && !status.deleteStatus) {
// If all the statuses cannot be found, this indicates the the repository has been successfully
// removed.
yield put(
updateDeleteProgress({
progress: WorkerReservedProgress.COMPLETED,
repoUri,
})
);
}

if (status.deleteStatus) {
yield put(
updateDeleteProgress({
progress: status.deleteStatus.progress,
repoUri,
})
);
return isInProgress(status.deleteStatus.progress);
}
},
pollRepoDeleteStatus
);

export function* watchRepoDeleteStatusPolling() {
// The repository delete status polling will be triggered by:
// * user click delete repository
// * repeating pollRepoDeleteStatus action by the poller itself.
yield takeEvery(
[String(deleteRepo), String(pollRepoDeleteStatus)],
handleRepoDeleteStatusPolling
);
}
8 changes: 4 additions & 4 deletions x-pack/plugins/code/public/sagas/status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ import { RootState } from '../reducers';

const matchSelector = (state: RootState) => state.route.match;

const pattern = (action: Action<any>) =>
export const cloneCompletedPattern = (action: Action<any>) =>
action.type === String(updateCloneProgress) &&
action.payload.progress === WorkerReservedProgress.COMPLETED;

const deletePattern = (action: Action<any>) =>
const deleteCompletedPattern = (action: Action<any>) =>
action.type === String(updateDeleteProgress) &&
action.payload.progress === WorkerReservedProgress.COMPLETED;

Expand All @@ -35,13 +35,13 @@ function* handleRepoCloneSuccess() {
}

export function* watchRepoCloneSuccess() {
yield takeEvery(pattern, handleRepoCloneSuccess);
yield takeEvery(cloneCompletedPattern, handleRepoCloneSuccess);
}

function* handleRepoDeleteFinished(action: any) {
yield put(deleteRepoFinished(action.payload.repoUri));
}

export function* watchRepoDeleteFinished() {
yield takeEvery(deletePattern, handleRepoDeleteFinished);
yield takeEvery(deleteCompletedPattern, handleRepoDeleteFinished);
}
6 changes: 3 additions & 3 deletions x-pack/plugins/code/public/selectors/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { FileTree } from '../../model';
import { FileTree, RepositoryUri } from '../../model';
import { RootState } from '../reducers';

export const getTree = (state: RootState) => state.file.tree;
Expand Down Expand Up @@ -35,8 +35,8 @@ export const repoUriSelector = (state: RootState) => {
return `${resource}/${org}/${repo}`;
};

export const statusSelector = (state: RootState) => {
return state.status.status[repoUriSelector(state)];
export const statusSelector = (state: RootState, repoUri: RepositoryUri) => {
return state.status.status[repoUri];
};

export const treeCommitsSelector = (state: RootState) => {
Expand Down
Loading