mirror of https://github.com/halo-dev/halo
refactor: reduce the number of failures due to conflict post update (#5604)
#### What type of PR is this? /kind improvement /area core /milestone 2.14.x #### What this PR does / why we need it: 减少文章更新因版本号冲突而失败的次数 #### Which issue(s) this PR fixes: Fixes #5579 #### Does this PR introduce a user-facing change? ```release-note None ```pull/5626/head v2.14.0-rc.1
parent
ec4c390e1f
commit
867d86b1a7
|
@ -1,16 +1,19 @@
|
||||||
package run.halo.app.content;
|
package run.halo.app.content;
|
||||||
|
|
||||||
import java.security.Principal;
|
import java.security.Principal;
|
||||||
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.dao.OptimisticLockingFailureException;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
|
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
|
||||||
import org.springframework.security.core.context.SecurityContext;
|
import org.springframework.security.core.context.SecurityContext;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
import reactor.util.retry.Retry;
|
||||||
import run.halo.app.core.extension.content.Snapshot;
|
import run.halo.app.core.extension.content.Snapshot;
|
||||||
import run.halo.app.extension.MetadataUtil;
|
import run.halo.app.extension.MetadataUtil;
|
||||||
import run.halo.app.extension.ReactiveExtensionClient;
|
import run.halo.app.extension.ReactiveExtensionClient;
|
||||||
|
@ -94,20 +97,23 @@ public abstract class AbstractContentService {
|
||||||
Assert.notNull(contentRequest, "The contentRequest must not be null");
|
Assert.notNull(contentRequest, "The contentRequest must not be null");
|
||||||
Assert.notNull(baseSnapshotName, "The baseSnapshotName must not be null");
|
Assert.notNull(baseSnapshotName, "The baseSnapshotName must not be null");
|
||||||
Assert.notNull(contentRequest.headSnapshotName(), "The headSnapshotName must not be null");
|
Assert.notNull(contentRequest.headSnapshotName(), "The headSnapshotName must not be null");
|
||||||
return client.fetch(Snapshot.class, contentRequest.headSnapshotName())
|
return Mono.defer(() -> client.fetch(Snapshot.class, contentRequest.headSnapshotName())
|
||||||
.flatMap(headSnapshot -> client.fetch(Snapshot.class, baseSnapshotName)
|
.flatMap(headSnapshot -> client.fetch(Snapshot.class, baseSnapshotName)
|
||||||
.map(baseSnapshot -> determineRawAndContentPatch(headSnapshot, baseSnapshot,
|
.map(baseSnapshot -> determineRawAndContentPatch(headSnapshot, baseSnapshot,
|
||||||
contentRequest)
|
contentRequest)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
.flatMap(headSnapshot -> getContextUsername()
|
||||||
|
.map(username -> {
|
||||||
|
Snapshot.addContributor(headSnapshot, username);
|
||||||
|
return headSnapshot;
|
||||||
|
})
|
||||||
|
.defaultIfEmpty(headSnapshot)
|
||||||
|
)
|
||||||
|
.flatMap(client::update)
|
||||||
)
|
)
|
||||||
.flatMap(headSnapshot -> getContextUsername()
|
.retryWhen(Retry.backoff(5, Duration.ofMillis(100))
|
||||||
.map(username -> {
|
.filter(throwable -> throwable instanceof OptimisticLockingFailureException))
|
||||||
Snapshot.addContributor(headSnapshot, username);
|
|
||||||
return headSnapshot;
|
|
||||||
})
|
|
||||||
.defaultIfEmpty(headSnapshot)
|
|
||||||
)
|
|
||||||
.flatMap(client::update)
|
|
||||||
.flatMap(head -> restoredContent(baseSnapshotName, head));
|
.flatMap(head -> restoredContent(baseSnapshotName, head));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -225,13 +225,11 @@ public class PostServiceImpl extends AbstractContentService implements PostServi
|
||||||
return client.update(post);
|
return client.update(post);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return Mono.defer(() -> updateContent(baseSnapshot, postRequest.contentRequest())
|
return updateContent(baseSnapshot, postRequest.contentRequest())
|
||||||
.flatMap(contentWrapper -> {
|
.flatMap(contentWrapper -> {
|
||||||
post.getSpec().setHeadSnapshot(contentWrapper.getSnapshotName());
|
post.getSpec().setHeadSnapshot(contentWrapper.getSnapshotName());
|
||||||
return client.update(post);
|
return client.update(post);
|
||||||
}))
|
});
|
||||||
.retryWhen(Retry.backoff(5, Duration.ofMillis(100))
|
|
||||||
.filter(throwable -> throwable instanceof OptimisticLockingFailureException));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -156,13 +156,11 @@ public class SinglePageServiceImpl extends AbstractContentService implements Sin
|
||||||
return client.update(page);
|
return client.update(page);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return Mono.defer(() -> updateContent(baseSnapshot, pageRequest.contentRequest())
|
return updateContent(baseSnapshot, pageRequest.contentRequest())
|
||||||
.flatMap(contentWrapper -> {
|
.flatMap(contentWrapper -> {
|
||||||
page.getSpec().setHeadSnapshot(contentWrapper.getSnapshotName());
|
page.getSpec().setHeadSnapshot(contentWrapper.getSnapshotName());
|
||||||
return client.update(page);
|
return client.update(page);
|
||||||
}))
|
});
|
||||||
.retryWhen(Retry.backoff(5, Duration.ofMillis(100))
|
|
||||||
.filter(throwable -> throwable instanceof OptimisticLockingFailureException));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Mono<ListedSinglePage> getListedSinglePage(SinglePage singlePage) {
|
private Mono<ListedSinglePage> getListedSinglePage(SinglePage singlePage) {
|
||||||
|
|
|
@ -193,11 +193,13 @@ public class PostEndpoint implements CustomEndpoint {
|
||||||
Mono<ServerResponse> updateContent(ServerRequest request) {
|
Mono<ServerResponse> updateContent(ServerRequest request) {
|
||||||
String postName = request.pathVariable("name");
|
String postName = request.pathVariable("name");
|
||||||
return request.bodyToMono(Content.class)
|
return request.bodyToMono(Content.class)
|
||||||
.flatMap(content -> client.fetch(Post.class, postName)
|
.flatMap(content -> Mono.defer(() -> client.fetch(Post.class, postName)
|
||||||
.flatMap(post -> {
|
.flatMap(post -> {
|
||||||
PostRequest postRequest = new PostRequest(post, content);
|
PostRequest postRequest = new PostRequest(post, content);
|
||||||
return postService.updatePost(postRequest);
|
return postService.updatePost(postRequest);
|
||||||
})
|
}))
|
||||||
|
.retryWhen(Retry.backoff(5, Duration.ofMillis(100))
|
||||||
|
.filter(throwable -> throwable instanceof OptimisticLockingFailureException))
|
||||||
)
|
)
|
||||||
.flatMap(post -> ServerResponse.ok().bodyValue(post));
|
.flatMap(post -> ServerResponse.ok().bodyValue(post));
|
||||||
}
|
}
|
||||||
|
|
|
@ -171,11 +171,13 @@ public class SinglePageEndpoint implements CustomEndpoint {
|
||||||
Mono<ServerResponse> updateContent(ServerRequest request) {
|
Mono<ServerResponse> updateContent(ServerRequest request) {
|
||||||
String pageName = request.pathVariable("name");
|
String pageName = request.pathVariable("name");
|
||||||
return request.bodyToMono(Content.class)
|
return request.bodyToMono(Content.class)
|
||||||
.flatMap(content -> client.fetch(SinglePage.class, pageName)
|
.flatMap(content -> Mono.defer(() -> client.fetch(SinglePage.class, pageName)
|
||||||
.flatMap(page -> {
|
.flatMap(page -> {
|
||||||
SinglePageRequest pageRequest = new SinglePageRequest(page, content);
|
SinglePageRequest pageRequest = new SinglePageRequest(page, content);
|
||||||
return singlePageService.update(pageRequest);
|
return singlePageService.update(pageRequest);
|
||||||
})
|
}))
|
||||||
|
.retryWhen(Retry.backoff(5, Duration.ofMillis(100))
|
||||||
|
.filter(throwable -> throwable instanceof OptimisticLockingFailureException))
|
||||||
)
|
)
|
||||||
.flatMap(post -> ServerResponse.ok().bodyValue(post));
|
.flatMap(post -> ServerResponse.ok().bodyValue(post));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue