Repository: honeydipper/honeydipper
Pull request #560 (2023-07-10 20:18:12)

chore(release): release
* able to detach a workflow
* hooks execution in parallel


Patch:
diff --git a/go.mod b/go.mod
index 20fec00..e0da844 100644
--- a/go.mod
+++ b/go.mod
@@ -3,10 +3,10 @@ module github.com/honeydipper/honeydipper
 go 1.18
 
 require (
-	cloud.google.com/go v0.110.2 // indirect
-	cloud.google.com/go/pubsub v1.30.0
-	cloud.google.com/go/spanner v1.45.0
-	cloud.google.com/go/storage v1.29.0
+	cloud.google.com/go v0.110.4 // indirect
+	cloud.google.com/go/pubsub v1.32.0
+	cloud.google.com/go/spanner v1.47.0
+	cloud.google.com/go/storage v1.30.1
 	github.com/DataDog/datadog-go v4.8.3+incompatible
 	github.com/Masterminds/goutils v1.1.1
 	github.com/casbin/casbin/v2 v2.41.0
@@ -21,7 +21,7 @@ require (
 	github.com/google/go-cmp v0.5.9 // indirect
 	github.com/google/gofuzz v1.2.0 // indirect
 	github.com/google/uuid v1.3.0
-	github.com/googleapis/gax-go/v2 v2.8.0
+	github.com/googleapis/gax-go/v2 v2.11.0
 	github.com/huandu/xstrings v1.4.0 // indirect
 	github.com/imdario/mergo v0.3.16
 	github.com/json-iterator/go v1.1.12 // indirect
@@ -38,8 +38,8 @@ require (
 	golang.org/x/oauth2 v0.8.0
 	golang.org/x/term v0.9.0
 	golang.org/x/text v0.10.0 // indirect
-	google.golang.org/api v0.123.0
-	google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc
+	google.golang.org/api v0.126.0
+	google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130
 	gopkg.in/h2non/gock.v1 v1.0.15
 	k8s.io/api v0.24.2
 	k8s.io/apimachinery v0.24.2
@@ -48,8 +48,8 @@ require (
 )
 
 require (
-	cloud.google.com/go/kms v1.10.1
-	cloud.google.com/go/secretmanager v1.10.0
+	cloud.google.com/go/kms v1.12.1
+	cloud.google.com/go/secretmanager v1.11.1
 	github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible // indirect
 	github.com/Microsoft/go-winio v0.6.1 // indirect
 	github.com/PuerkitoBio/purell v1.1.1 // indirect
@@ -91,8 +91,8 @@ require (
 	go.opentelemetry.io/otel/trace v1.3.0 // indirect
 	golang.org/x/time v0.3.0 // indirect
 	google.golang.org/appengine v1.6.7 // indirect
-	google.golang.org/grpc v1.55.0 // indirect
-	google.golang.org/protobuf v1.30.0 // indirect
+	google.golang.org/grpc v1.56.2 // indirect
+	google.golang.org/protobuf v1.31.0 // indirect
 	gopkg.in/inf.v0 v0.9.1 // indirect
 	gopkg.in/warnings.v0 v0.1.2 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect
@@ -111,13 +111,13 @@ require (
 	github.com/go-git/go-git/v5 v5.7.0
 	github.com/go-redis/redismock/v8 v8.0.6
 	github.com/golang-jwt/jwt/v5 v5.0.0
-	golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1
+	golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df
 )
 
 require (
-	cloud.google.com/go/compute v1.19.3 // indirect
-	cloud.google.com/go/iam v0.13.0 // indirect
-	cloud.google.com/go/longrunning v0.4.2 // indirect
+	cloud.google.com/go/compute v1.20.1 // indirect
+	cloud.google.com/go/iam v1.1.0 // indirect
+	cloud.google.com/go/longrunning v0.5.1 // indirect
 	github.com/Masterminds/semver/v3 v3.2.0 // indirect
 	github.com/ProtonMail/go-crypto v0.0.0-20230528122434-6f98819771a1 // indirect
 	github.com/acomagu/bufpipe v1.0.4 // indirect
@@ -143,6 +143,6 @@ require (
 	golang.org/x/sys v0.9.0 // indirect
 	golang.org/x/tools v0.9.3 // indirect
 	golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
-	google.golang.org/genproto/googleapis/api v0.0.0-20230526203410-71b5a4ffd15e // indirect
-	google.golang.org/genproto/googleapis/rpc v0.0.0-20230526203410-71b5a4ffd15e // indirect
+	google.golang.org/genproto/googleapis/api v0.0.0-20230629202037-9506855d4529 // indirect
+	google.golang.org/genproto/googleapis/rpc v0.0.0-20230629202037-9506855d4529 // indirect
 )
diff --git a/go.sum b/go.sum
index 4b86fc8..7c7c638 100644
--- a/go.sum
+++ b/go.sum
@@ -20,6 +20,8 @@ cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb
 cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
 cloud.google.com/go v0.110.2 h1:sdFPBr6xG9/wkBbfhmUz/JmZC7X6LavQgcrVINrKiVA=
 cloud.google.com/go v0.110.2/go.mod h1:k04UEeEtb6ZBRTv3dZz4CeJC3jKGxyhl0sAiVVquxiw=
+cloud.google.com/go v0.110.4 h1:1JYyxKMN9hd5dR2MYTPWkGUgcoxVVhg0LKNKEo0qvmk=
+cloud.google.com/go v0.110.4/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI=
 cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
 cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
 cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
@@ -28,28 +30,42 @@ cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4g
 cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
 cloud.google.com/go/compute v1.19.3 h1:DcTwsFgGev/wV5+q8o2fzgcHOaac+DKGC91ZlvpsQds=
 cloud.google.com/go/compute v1.19.3/go.mod h1:qxvISKp/gYnXkSAD1ppcSOveRAmzxicEv/JlizULFrI=
+cloud.google.com/go/compute v1.20.1 h1:6aKEtlUiwEpJzM001l0yFkpXmUVXaN8W+fbkb2AZNbg=
+cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM=
 cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
 cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
 cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
 cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
 cloud.google.com/go/iam v0.13.0 h1:+CmB+K0J/33d0zSQ9SlFWUeCCEn5XJA0ZMZ3pHE9u8k=
 cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0=
+cloud.google.com/go/iam v1.1.0 h1:67gSqaPukx7O8WLLHMa0PNs3EBGd2eE4d+psbO/CO94=
+cloud.google.com/go/iam v1.1.0/go.mod h1:nxdHjaKfCr7fNYx/HJMM8LgiMugmveWlkatear5gVyk=
 cloud.google.com/go/kms v1.10.1 h1:7hm1bRqGCA1GBRQUrp831TwJ9TWhP+tvLuP497CQS2g=
 cloud.google.com/go/kms v1.10.1/go.mod h1:rIWk/TryCkR59GMC3YtHtXeLzd634lBbKenvyySAyYI=
+cloud.google.com/go/kms v1.12.1 h1:xZmZuwy2cwzsocmKDOPu4BL7umg8QXagQx6fKVmf45U=
+cloud.google.com/go/kms v1.12.1/go.mod h1:c9J991h5DTl+kg7gi3MYomh12YEENGrf48ee/N/2CDM=
 cloud.google.com/go/logging v1.7.0 h1:CJYxlNNNNAMkHp9em/YEXcfJg+rPDg7YfwoRpMU+t5I=
 cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M=
 cloud.google.com/go/longrunning v0.4.2 h1:WDKiiNXFTaQ6qz/G8FCOkuY9kJmOJGY67wPUC1M2RbE=
 cloud.google.com/go/longrunning v0.4.2/go.mod h1:OHrnaYyLUV6oqwh0xiS7e5sLQhP1m0QU9R+WhGDMgIQ=
+cloud.google.com/go/longrunning v0.5.1 h1:Fr7TXftcqTudoyRJa113hyaqlGdiBQkp0Gq7tErFDWI=
+cloud.google.com/go/longrunning v0.5.1/go.mod h1:spvimkwdz6SPWKEt/XBij79E9fiTkHSQl/fRUUQJYJc=
 cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
 cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
 cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
 cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
 cloud.google.com/go/pubsub v1.30.0 h1:vCge8m7aUKBJYOgrZp7EsNDf6QMd2CAlXZqWTn3yq6s=
 cloud.google.com/go/pubsub v1.30.0/go.mod h1:qWi1OPS0B+b5L+Sg6Gmc9zD1Y+HaM0MdUr7LsupY1P4=
+cloud.google.com/go/pubsub v1.32.0 h1:JOEkgEYBuUTHSyHS4TcqOFuWr+vD6qO/imsFqShUCp4=
+cloud.google.com/go/pubsub v1.32.0/go.mod h1:f+w71I33OMyxf9VpMVcZbnG5KSUkCOUHYpFd5U1GdRc=
 cloud.google.com/go/secretmanager v1.10.0 h1:pu03bha7ukxF8otyPKTFdDz+rr9sE3YauS5PliDXK60=
 cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU=
+cloud.google.com/go/secretmanager v1.11.1 h1:cLTCwAjFh9fKvU6F13Y4L9vPcx9yiWPyWXE4+zkuEQs=
+cloud.google.com/go/secretmanager v1.11.1/go.mod h1:znq9JlXgTNdBeQk9TBW/FnR/W4uChEKGeqQWAJ8SXFw=
 cloud.google.com/go/spanner v1.45.0 h1:7VdjZ8zj4sHbDw55atp5dfY6kn1j9sam9DRNpPQhqR4=
 cloud.google.com/go/spanner v1.45.0/go.mod h1:FIws5LowYz8YAE1J8fOS7DJup8ff7xJeetWEo5REA2M=
+cloud.google.com/go/spanner v1.47.0 h1:aqiMP8dhsEXgn9K5EZBWxPG7dxIiyM2VaikqeU4iteg=
+cloud.google.com/go/spanner v1.47.0/go.mod h1:IXsJwVW2j4UKs0eYDqodab6HgGuA1bViSqW4uH9lfUI=
 cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
 cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
 cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
@@ -57,6 +73,8 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX
 cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
 cloud.google.com/go/storage v1.29.0 h1:6weCgzRvMg7lzuUurI4697AqIRPU1SvzHhynwpW31jI=
 cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4=
+cloud.google.com/go/storage v1.30.1 h1:uOdMxAs8HExqBlnLtnQyP0YkvbiDpdGShGKtx6U/oNM=
+cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E=
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
 github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
 github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA=
@@ -307,6 +325,8 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+
 github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
 github.com/googleapis/gax-go/v2 v2.8.0 h1:UBtEZqx1bjXtOQ5BVTkuYghXrr3N4V123VKJK67vJZc=
 github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI=
+github.com/googleapis/gax-go/v2 v2.11.0 h1:9V9PWXEsWnPpQhu/PeQIkS4eGzMlTLGgt80cUUI8Ki4=
+github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI=
 github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
 github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
 github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
@@ -523,6 +543,8 @@ golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EH
 golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
 golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
 golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
+golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME=
+golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -803,6 +825,8 @@ google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBz
 google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
 google.golang.org/api v0.123.0 h1:yHVU//vA+qkOhm4reEC9LtzHVUCN/IqqNRl1iQ9xE20=
 google.golang.org/api v0.123.0/go.mod h1:gcitW0lvnyWjSp9nKxAbdHKIZ6vF4aajGueeslZOyms=
+google.golang.org/api v0.126.0 h1:q4GJq+cAdMAC7XP7njvQ4tvohGLiSlytuL4BQxbIZ+o=
+google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@@ -854,10 +878,16 @@ google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6D
 google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
 google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc h1:8DyZCyvI8mE1IdLy/60bS+52xfymkE72wv1asokgtao=
 google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64=
+google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130 h1:Au6te5hbKUV8pIYWHqOUZ1pva5qK/rwbIhoXEUB9Lu8=
+google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:O9kGHb51iE/nOGvQaDUuadVYqovW56s5emA88lQnj6Y=
 google.golang.org/genproto/googleapis/api v0.0.0-20230526203410-71b5a4ffd15e h1:AZX1ra8YbFMSb7+1pI8S9v4rrgRR7jU1FmuFSSjTVcQ=
 google.golang.org/genproto/googleapis/api v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig=
+google.golang.org/genproto/googleapis/api v0.0.0-20230629202037-9506855d4529 h1:s5YSX+ZH5b5vS9rnpGymvIyMpLRJizowqDlOuyjXnTk=
+google.golang.org/genproto/googleapis/api v0.0.0-20230629202037-9506855d4529/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig=
 google.golang.org/genproto/googleapis/rpc v0.0.0-20230526203410-71b5a4ffd15e h1:NumxXLPfHSndr3wBBdeKiVHjGVFzi9RX2HwwQke94iY=
 google.golang.org/genproto/googleapis/rpc v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20230629202037-9506855d4529 h1:DEH99RbiLZhMxrpEJCZ0A+wdTe0EOgou/poSLx9vWf4=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20230629202037-9506855d4529/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
 google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@@ -880,6 +910,8 @@ google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG
 google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
 google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag=
 google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8=
+google.golang.org/grpc v1.56.2 h1:fVRFRnXvU+x6C4IlHZewvJOVHoOv1TUuQyoRsYnB4bI=
+google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
 google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
 google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -895,6 +927,8 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
 google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
 google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
 google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
+google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/internal/config/schema.go b/internal/config/schema.go
index 4f11c5a..939b034 100644
--- a/internal/config/schema.go
+++ b/internal/config/schema.go
@@ -95,6 +95,7 @@ type Workflow struct {
 	Steps        []Workflow
 	Threads      []Workflow
 	Wait         string
+	Detach       bool
 
 	Switch  string
 	Cases   map[string]interface{}
diff --git a/internal/daemon/daemon.go b/internal/daemon/daemon.go
index d6cab76..725d7f6 100644
--- a/internal/daemon/daemon.go
+++ b/internal/daemon/daemon.go
@@ -46,3 +46,12 @@ func Run(cfg *config.Config) {
 	OnStart()
 	cfg.Watch()
 }
+
+// Go launches a go routine with necessary prep and cleanup in the wrapper.
+func Go(f func()) {
+	Children.Add(1)
+	go func() {
+		defer Children.Done()
+		f()
+	}()
+}
diff --git a/internal/workflow/execute.go b/internal/workflow/execute.go
index 982182b..f6b1528 100644
--- a/internal/workflow/execute.go
+++ b/internal/workflow/execute.go
@@ -17,6 +17,12 @@ import (
 	"github.com/mitchellh/mapstructure"
 )
 
+var Success = &dipper.Message{
+	Labels: map[string]string{
+		"status": SessionStatusSuccess,
+	},
+}
+
 // execute is the entry point of the workflow.
 func (w *Session) execute(msg *dipper.Message) {
 	w.fireHook("on_session", msg)
@@ -67,11 +73,7 @@ func (w *Session) execute(msg *dipper.Message) {
 // noop continues the workflow as doing nothing.
 func (w *Session) noop(msg *dipper.Message) {
 	if msg.Labels["status"] != "success" {
-		msg = &dipper.Message{
-			Labels: map[string]string{
-				"status": SessionStatusSuccess,
-			},
-		}
+		msg = Success
 	}
 	if w.ID != "" {
 		w.continueExec(msg, nil)
@@ -262,8 +264,8 @@ func (w *Session) executeSwitch(msg *dipper.Message) {
 	w.noop(msg)
 }
 
-// executeAction takes actions for a single iteration in a single loop round.
-func (w *Session) executeAction(msg *dipper.Message) {
+// processActionHooks process the action hooks.
+func (w *Session) processActionHooks(msg *dipper.Message) bool {
 	switch {
 	case w.workflow.Workflow != "":
 		fallthrough
@@ -284,22 +286,38 @@ func (w *Session) executeAction(msg *dipper.Message) {
 		if w.currentHook == "" {
 			w.fireHook("on_action", msg)
 		}
-		if w.currentHook != "" {
-			return
-		}
 	}
 	// no action hooks if workflow is noop
 
+	return w.currentHook != ""
+}
+
+// executeAction takes actions for a single iteration in a single loop round.
+func (w *Session) executeAction(msg *dipper.Message) {
+	if w.processActionHooks(msg) { // hook in progress
+		return
+	}
+
 	switch {
 	case w.workflow.Workflow != "":
 		envData := w.buildEnvData(msg)
 		work := dipper.InterpolateStr(w.workflow.Workflow, envData)
 		w.performing = work
 		if !w.isHook && w.workflow.Name == "" {
-			w.ctx["_meta_name"] = work
+			w.ctx["_meta_name"] = "calling " + work
 		}
 		child := w.createChildSessionWithName(work, msg)
-		child.execute(msg)
+		if w.workflow.Detach {
+			child.parent = ""
+			delete(child.ctx, "resume_token")
+			daemon.Go(func() {
+				defer dipper.SafeExitOnError("Failed in execute detached workflow %+v", w.workflow.Workflow)
+				child.execute(msg)
+			})
+			w.continueExec(Success, nil)
+		} else {
+			child.execute(msg)
+		}
 	case w.isFunction():
 		w.performing = "function"
 		f := w.interpolateFunction(&w.workflow.Function, msg)
@@ -325,11 +343,7 @@ func (w *Session) executeAction(msg *dipper.Message) {
 		w.performing = "switch"
 		w.executeSwitch(msg)
 	default:
-		w.continueExec(&dipper.Message{
-			Labels: map[string]string{
-				"status": SessionStatusSuccess,
-			},
-		}, nil)
+		w.continueExec(Success, nil)
 	}
 }
 
diff --git a/internal/workflow/hooks.go b/internal/workflow/hooks.go
index 5458c11..07df3c5 100644
--- a/internal/workflow/hooks.go
+++ b/internal/workflow/hooks.go
@@ -62,7 +62,7 @@ func (w *Session) executeHook(msg *dipper.Message, hookBlock interface{}) {
 			Context: SessionContextHooks,
 		}
 		for i := 0; i < v.Len(); i++ {
-			childWf.Steps = append(childWf.Steps, config.Workflow{Workflow: v.Index(i).Interface().(string)})
+			childWf.Threads = append(childWf.Threads, config.Workflow{Workflow: v.Index(i).Interface().(string)})
 		}
 		child = w.createChildSession(&childWf, msg)
 	}
diff --git a/internal/workflow/session.go b/internal/workflow/session.go
index 6b30533..6fcacc0 100644
--- a/internal/workflow/session.go
+++ b/internal/workflow/session.go
@@ -299,7 +299,7 @@ func (w *Session) injectLocalCTX(msg *dipper.Message) {
 func (w *Session) interpolateWorkflow(msg *dipper.Message) {
 	v := w.workflow
 	envData := w.buildEnvData(msg)
-	ret := config.Workflow{}
+	ret := *v
 
 	ret.Name = dipper.InterpolateStr(v.Name, envData)
 	ret.Description = dipper.InterpolateStr(v.Description, envData)
@@ -324,32 +324,33 @@ func (w *Session) interpolateWorkflow(msg *dipper.Message) {
 		ret.IterateParallel = []interface{}{}
 	}
 
-	ret.While = v.While                     // repeatedly interpolated later
-	ret.WhileAny = v.WhileAny               // repeatedly interpolated later
-	ret.WhileMatch = v.WhileMatch           // repeatedly interpolated later
-	ret.Until = v.Until                     // repeatedly interpolated later
-	ret.UntilAll = v.UntilAll               // repeatedly interpolated later
-	ret.UntilMatch = v.UntilMatch           // repeatedly interpolated later
-	ret.Else = v.Else                       // delayed
-	ret.Workflow = v.Workflow               // delayed
-	ret.Function = v.Function               // delayed
-	ret.Steps = v.Steps                     // delayed
-	ret.Threads = v.Threads                 // delayed
-	ret.Export = v.Export                   // delayed
-	ret.ExportOnSuccess = v.ExportOnSuccess // delayed
-	ret.ExportOnFailure = v.ExportOnFailure // delayed
-	ret.ExportOnError = v.ExportOnError     // delayed
-	ret.Switch = v.Switch                   // delayed
-	ret.Cases = v.Cases                     // delayed
-	ret.Default = v.Default                 // delayed
-
-	ret.Context = v.Context     // interpolated in initCTX
-	ret.Contexts = v.Contexts   // interpolated in initCTX
-	ret.NoExport = v.NoExport   // no interpolation
-	ret.IterateAs = v.IterateAs // no interpolation
-	ret.OnError = v.OnError     // no interpolation
-	ret.OnFailure = v.OnFailure // no interpolation
-	ret.Local = v.Local         // no interpolation
+	// ret.While = v.While                     // repeatedly interpolated later
+	// ret.WhileAny = v.WhileAny               // repeatedly interpolated later
+	// ret.WhileMatch = v.WhileMatch           // repeatedly interpolated later
+	// ret.Until = v.Until                     // repeatedly interpolated later
+	// ret.UntilAll = v.UntilAll               // repeatedly interpolated later
+	// ret.UntilMatch = v.UntilMatch           // repeatedly interpolated later
+	// ret.Else = v.Else                       // delayed
+	// ret.Workflow = v.Workflow               // delayed
+	// ret.Function = v.Function               // delayed
+	// ret.Steps = v.Steps                     // delayed
+	// ret.Threads = v.Threads                 // delayed
+	// ret.Export = v.Export                   // delayed
+	// ret.ExportOnSuccess = v.ExportOnSuccess // delayed
+	// ret.ExportOnFailure = v.ExportOnFailure // delayed
+	// ret.ExportOnError = v.ExportOnError     // delayed
+	// ret.Switch = v.Switch                   // delayed
+	// ret.Cases = v.Cases                     // delayed
+	// ret.Default = v.Default                 // delayed
+
+	// ret.Context = v.Context     // interpolated in initCTX
+	// ret.Contexts = v.Contexts   // interpolated in initCTX
+	// ret.NoExport = v.NoExport   // no interpolation
+	// ret.IterateAs = v.IterateAs // no interpolation
+	// ret.OnError = v.OnError     // no interpolation
+	// ret.OnFailure = v.OnFailure // no interpolation
+	// ret.Local = v.Local         // no interpolation
+	// ret.Detach = v.Detach       // no interpolation
 
 	w.workflow = &ret
 }
@@ -389,7 +390,7 @@ func (w *Session) setPerforming(performing string) string {
 	case wf.CallDriver != "":
 		w.performing = wf.CallDriver
 	case wf.Workflow != "":
-		w.performing = wf.Workflow
+		w.performing = "calling " + wf.Workflow
 	case w.isIteration():
 		w.performing = "iterating"
 	case w.isLoop():


Test patch:
diff --git a/internal/workflow/session_hook_test.go b/internal/workflow/session_hook_test.go
index b49dc0d..b7864e4 100644
--- a/internal/workflow/session_hook_test.go
+++ b/internal/workflow/session_hook_test.go
@@ -308,6 +308,7 @@ func TestOnFailureHook(t *testing.T) {
 				},
 				"ctx": map[string]interface{}{},
 				"asserts": func() {
+					mockHelper.EXPECT().GetDaemonID().Return("")
 					mockHelper.EXPECT().SendMessage(gomock.Eq(&dipper.Message{
 						Channel: "eventbus",
 						Subject: "command",
@@ -316,10 +317,10 @@ func TestOnFailureHook(t *testing.T) {
 						},
 						Payload: map[string]interface{}{
 							"ctx": map[string]interface{}{
-								"_meta_desc":   "",
-								"_meta_name":   "foo.failure",
-								"resume_token": "//0",
-								"step_number":  int32(0),
+								"_meta_desc":    "",
+								"_meta_name":    "foo.failure",
+								"resume_token":  "//2",
+								"thread_number": 0,
 							},
 							"data":  map[string]interface{}{},
 							"event": map[string]interface{}{},
diff --git a/internal/workflow/store_test.go b/internal/workflow/store_test.go
index 4469b5b..f3b32df 100644
--- a/internal/workflow/store_test.go
+++ b/internal/workflow/store_test.go
@@ -70,7 +70,7 @@ func TestNewSession(t *testing.T) {
 				Workflow: "test",
 			},
 			"asserts": func() {
-				assert.Equal(t, "test", session.performing)
+				assert.Equal(t, "calling test", session.performing)
 				assert.Equal(t, "0", session.parent)
 				session.save()
 				assert.Equal(t, "1", session.ID)