blob: b622cb1cca3036c4f13ed804cd63676b22a070c1 [file]
#
# 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.
#
name: Docker example
on:
workflow_call:
inputs:
java-version:
default: '8'
required: false
type: string
jdk-distro:
default: 'temurin'
required: false
type: string
jobs:
docker:
runs-on: ubuntu-latest
name: speculate fail tasks
steps:
- name: Checkout project
uses: actions/checkout@v3
- name: Set up JDK ${{ inputs.java-version }}
uses: actions/setup-java@v3
with:
java-version: ${{ inputs.java-version }}
distribution: ${{ inputs.jdk-distro }}
- name: Cache local Maven repository
uses: actions/cache@v3
with:
path: ~/.m2/repository
key: mvn-${{ inputs.java-version }}-docker-${{ hashFiles('**/pom.xml') }}
restore-keys: |
mvn-${{ inputs.java-version }}-docker-
- name: Build the docker images
run: ./deploy/docker/build.sh
shell: bash
- name: Start the docker cluster
id: up
run: |
docker compose -f deploy/docker/docker-compose.yml up --wait --wait-timeout 60 \
--scale coordinator=2 --scale shuffle-server=4 --scale spark-worker=5
# check all rss containers are up
healthy="$(docker container ls | grep rss-server-example | grep "(healthy)" | wc -l)"
if [ "$healthy" == "7" ]
then
echo "All RSS containers up"
else
echo "::error::Could not bring up Docker cluster"
exit 1
fi
shell: bash
- name: Prepare example Spark app
run: |
cat << EOL > example.scala
import org.apache.spark.TaskContext
import org.apache.spark.sql.SaveMode
// fails iteration (at the end) or delays iteration (each element)
// failing tasks negates iterator values, shuffle data of failing task must not leak into next stage
case class FaultyIterator(it: Iterator[java.lang.Long], fail: Boolean, sleep: Option[Int]) extends Iterator[java.lang.Long] {
override def hasNext: Boolean = it.hasNext || fail
override def next(): java.lang.Long = {
// delay iteration if requested
if (sleep.isDefined) {
val start = System.nanoTime()
while (start + sleep.get >= System.nanoTime()) { }
}
// fail at the end if requested
if (fail && !it.hasNext) throw new RuntimeException()
// just iterate
if (fail) {
-it.next()
} else {
it.next()
}
}
}
spark.range(0, 10000000, 1, 100) \
.mapPartitions { it =>
val ctx = TaskContext.get();
FaultyIterator(
it,
// we fail task two 3 times
(ctx.partitionId == 2 && ctx.attemptNumber < 3),
// and delay attempt 4 so we see a speculative execution
Some(ctx.partitionId == 2 && ctx.attemptNumber >= 3).filter(v => v).map(_ => 250000)
)
} \
.groupBy(($"value" / 1000000).cast("int")) \
.as[Long, Long] \
.mapGroups{(id, it) => (id, it.length)} \
.sort("_1") \
.write \
.mode(SaveMode.Overwrite) \
.csv("/shared/result.csv")
EOL
docker cp example.scala rss-spark-master-1:/
shell: bash
- name: Run example Spark app
run: |
docker exec rss-spark-master-1 /bin/bash -c "cat /example.scala | /opt/spark/bin/spark-shell \
--master spark://rss-spark-master-1:7077 \
--conf spark.serializer=org.apache.spark.serializer.KryoSerializer \
--conf spark.shuffle.manager=org.apache.spark.shuffle.RssShuffleManager \
--conf spark.rss.coordinator.quorum=rss-coordinator-1:19999,rss-coordinator-2:19999 \
--conf spark.rss.storage.type=MEMORY_LOCALFILE \
--conf spark.task.maxFailures=4 \
--conf spark.speculation=true"
shell: bash
- name: Assert result
run: |
docker exec rss-spark-master-1 bash -c "cat /shared/result.csv/*.csv" > ./result.csv
cat << EOL | diff -y - result.csv
0,1000000
1,1000000
2,1000000
3,1000000
4,1000000
5,1000000
6,1000000
7,1000000
8,1000000
9,1000000
EOL
shell: bash
- name: Stop the docker cluster
if: always() && steps.up.outcome == 'success'
run: docker compose -f deploy/docker/docker-compose.yml down
shell: bash