[SCB-2189]uploading multiple files using RestTemplate randomly fail (#2233)

diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestUploadSchema.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestUploadSchema.java
new file mode 100644
index 0000000..cebd61c
--- /dev/null
+++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestUploadSchema.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.servicecomb.demo.springmvc.client;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.UUID;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.servicecomb.demo.CategorizedTestCase;
+import org.apache.servicecomb.demo.TestMgr;
+import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder;
+import org.springframework.core.io.FileSystemResource;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.stereotype.Component;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.client.RestTemplate;
+
+@Component
+public class TestUploadSchema implements CategorizedTestCase {
+  @Override
+  public void testRestTransport() throws Exception {
+    testServerStartupSuccess();
+    testUploadMultiBigFiles();
+  }
+
+  private void testServerStartupSuccess() {
+    RestTemplate template = RestTemplateBuilder.create();
+    boolean result = template.getForObject("servicecomb://springmvc/upload/isServerStartUpSuccess", Boolean.class);
+    TestMgr.check(result, true);
+  }
+
+  private void testUploadMultiBigFiles() throws Exception {
+    final int fileNum = 5;
+    List<File> files = new ArrayList<>(fileNum);
+
+    String fileName = UUID.randomUUID().toString();
+    for (int i = 0; i < fileNum; i++) {
+      File tempFile = new File("random-client-" + fileName + i);
+      files.add(tempFile);
+      FileOutputStream fo = new FileOutputStream(tempFile);
+      byte[] data = new byte[1024 * 1024 * 10];
+      Arrays.fill(data, (byte) 33);
+      IOUtils.write(data, fo);
+      fo.close();
+    }
+
+    RestTemplate template = RestTemplateBuilder.create();
+
+    MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
+    for (int i = 0; i < fileNum; i++) {
+      map.add("files", new FileSystemResource(files.get(i)));
+    }
+
+    HttpHeaders headers = new HttpHeaders();
+    headers.setContentType(org.springframework.http.MediaType.MULTIPART_FORM_DATA);
+    HttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<>(map, headers);
+
+    String result = template.postForObject("servicecomb://springmvc/upload/fileUpload", entity, String.class);
+    TestMgr.check(result, "success");
+  }
+}
diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ProducerTestsAfterBootup.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ProducerTestsAfterBootup.java
index d8d1bdd..9ca48e7 100644
--- a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ProducerTestsAfterBootup.java
+++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ProducerTestsAfterBootup.java
@@ -89,7 +89,7 @@
   }
 
   public void testRegisteredBasePath() {
-    TestMgr.check(15, RegistrationManager.INSTANCE.getMicroservice().getPaths().size());
+    TestMgr.check(16, RegistrationManager.INSTANCE.getMicroservice().getPaths().size());
   }
 
   private String getSwaggerContent(Swagger swagger) {
diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/UploadSchema.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/UploadSchema.java
new file mode 100644
index 0000000..24ec3f2
--- /dev/null
+++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/UploadSchema.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.servicecomb.demo.springmvc.server;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.UUID;
+
+import org.apache.servicecomb.demo.TestMgr;
+import org.apache.servicecomb.provider.rest.common.RestSchema;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestPart;
+import org.springframework.web.multipart.MultipartFile;
+
+@RestSchema(schemaId = "UploadSchema")
+@RequestMapping(path = "/upload", produces = MediaType.APPLICATION_JSON_VALUE)
+public class UploadSchema {
+  @PostMapping(path = "/fileUpload", produces = MediaType.TEXT_PLAIN_VALUE,
+      consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+  public String fileUpload(@RequestPart(name = "files") List<MultipartFile> files) {
+    try {
+      String fileName = UUID.randomUUID().toString();
+      int index = 0;
+      for (MultipartFile file : files) {
+        File tempFile = new File("random-server-" + fileName + index);
+        file.transferTo(tempFile);
+        index++;
+      }
+      return "success";
+    } catch (IOException e) {
+      return "failed";
+    }
+  }
+
+  @GetMapping(path = "/isServerStartUpSuccess")
+  public boolean isServerStartUpSuccess() {
+    return TestMgr.isSuccess();
+  }
+}
diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/stream/PumpFromPart.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/stream/PumpFromPart.java
index d76e7f2..cc147c1 100644
--- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/stream/PumpFromPart.java
+++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/stream/PumpFromPart.java
@@ -23,12 +23,12 @@
 
 import javax.servlet.http.Part;
 
-import io.vertx.core.Handler;
 import org.apache.commons.io.IOUtils;
 import org.apache.servicecomb.foundation.vertx.http.DownloadUtils;
 import org.apache.servicecomb.foundation.vertx.http.ReadStreamPart;
 
 import io.vertx.core.Context;
+import io.vertx.core.Handler;
 import io.vertx.core.buffer.Buffer;
 import io.vertx.core.streams.ReadStream;
 import io.vertx.core.streams.WriteStream;
@@ -66,7 +66,13 @@
   public CompletableFuture<Void> toWriteStream(WriteStream<Buffer> writeStream, Handler<Throwable> throwableHandler) {
     return prepareReadStream()
         .thenCompose(readStream -> new PumpCommon().pump(context, readStream, writeStream, throwableHandler))
-        .whenComplete((v, e) -> DownloadUtils.clearPartResource(part));
+        .whenComplete((v, e) -> {
+          DownloadUtils.clearPartResource(part);
+          // PumpImpl will add drainHandler to writeStream,
+          // in order to support write multiple files to same writeStream,
+          // need reset after one stream is successful.
+          writeStream.drainHandler(null);
+        });
   }
 
   public CompletableFuture<Void> toOutputStream(OutputStream outputStream, boolean autoCloseOutputStream) {