Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: roadrunner-server/endure
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v1.4.6
Choose a base ref
...
head repository: roadrunner-server/endure
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v2.0.0
Choose a head ref

Commits on Dec 1, 2022

  1. deps: update dependencies

    rustatian committed Dec 1, 2022
    Copy the full SHA
    4355458 View commit details

Commits on Dec 22, 2022

  1. Copy the full SHA
    f28ddd1 View commit details

Commits on Jan 2, 2023

  1. feat: v2

    Signed-off-by: Valery Piashchynski <piashchynski.valery@gmail.com>
    rustatian committed Jan 2, 2023
    Copy the full SHA
    aa0fc0e View commit details
  2. Copy the full SHA
    03cf9ad View commit details
  3. update samples

    Signed-off-by: Valery Piashchynski <piashchynski.valery@gmail.com>
    rustatian committed Jan 2, 2023
    Copy the full SHA
    4fdcb9a View commit details
  4. update init function, Update registar with initialized values

    Signed-off-by: Valery Piashchynski <piashchynski.valery@gmail.com>
    rustatian committed Jan 2, 2023
    Copy the full SHA
    0e3b6ba View commit details

Commits on Jan 3, 2023

  1. pre-release tests

    Signed-off-by: Valery Piashchynski <piashchynski.valery@gmail.com>
    rustatian committed Jan 3, 2023
    Copy the full SHA
    bc80e86 View commit details
  2. ci: correct tests

    Signed-off-by: Valery Piashchynski <piashchynski.valery@gmail.com>
    rustatian committed Jan 3, 2023
    Copy the full SHA
    8d431da View commit details

Commits on Jan 4, 2023

  1. more tests, dep.OutType -> dep.Bind

    Signed-off-by: Valery Piashchynski <piashchynski.valery@gmail.com>
    rustatian committed Jan 4, 2023
    Copy the full SHA
    b6fb775 View commit details
  2. more tests

    Signed-off-by: Valery Piashchynski <piashchynski.valery@gmail.com>
    rustatian committed Jan 4, 2023
    Copy the full SHA
    72aafe3 View commit details
  3. Update README

    Signed-off-by: Valery Piashchynski <piashchynski.valery@gmail.com>
    rustatian committed Jan 4, 2023
    Copy the full SHA
    ae5dcde View commit details
  4. [#133]: feat: endure v2

    rustatian authored Jan 4, 2023
    Copy the full SHA
    9091c92 View commit details
  5. Update README.md

    rustatian authored Jan 4, 2023
    Copy the full SHA
    d8b1ad2 View commit details

Commits on Jan 5, 2023

  1. chore(test): add more tests

    Signed-off-by: Valery Piashchynski <piashchynski.valery@gmail.com>
    rustatian committed Jan 5, 2023
    Copy the full SHA
    022b2b8 View commit details

Commits on Jan 6, 2023

  1. Update README.md

    rustatian authored Jan 6, 2023
    Copy the full SHA
    2537ae1 View commit details

Commits on Jan 7, 2023

  1. chore: update slog logger, protect some operations from the

    out-of-bounds access
    
    Signed-off-by: Valery Piashchynski <piashchynski.valery@gmail.com>
    rustatian committed Jan 7, 2023
    Copy the full SHA
    ff4fa57 View commit details
  2. chore: remove LGTM from the README

    Signed-off-by: Valery Piashchynski <piashchynski.valery@gmail.com>
    rustatian committed Jan 7, 2023
    Copy the full SHA
    9aed8e3 View commit details
  3. chore: update godoc link

    Signed-off-by: Valery Piashchynski <piashchynski.valery@gmail.com>
    rustatian committed Jan 7, 2023
    Copy the full SHA
    ff0dbd7 View commit details
  4. chore: remove redundant continue

    Signed-off-by: Valery Piashchynski <piashchynski.valery@gmail.com>
    rustatian committed Jan 7, 2023
    Copy the full SHA
    1980c4c View commit details

Commits on Jan 8, 2023

  1. chore: add some helpers to identify the empty graph

    Signed-off-by: Valery Piashchynski <piashchynski.valery@gmail.com>
    rustatian committed Jan 8, 2023
    Copy the full SHA
    55c6a0c View commit details

Commits on Jan 21, 2023

  1. Copy the full SHA
    0b57348 View commit details
Showing with 3,734 additions and 4,845 deletions.
  1. +1 −1 .github/workflows/linux.yml
  2. +1 −1 .github/workflows/macOS.yml
  3. +1 −1 .github/workflows/windows.yml
  4. +6 −1 Makefile
  5. +64 −79 README.md
  6. +42 −0 collects.go
  7. +23 −10 {pkg/container → }/container.go
  8. +25 −0 dep/in.go
  9. +21 −0 dep/in_test.go
  10. +66 −0 dep/out.go
  11. +32 −0 dep/out_test.go
  12. +0 −712 docs/endure_arch.drawio
  13. +125 −0 edges.go
  14. +274 −0 endure.go
  15. +9 −10 examples/sample_1/go.mod
  16. +12 −64 examples/sample_1/go.sum
  17. +10 −12 examples/sample_1/main.go
  18. +7 −4 examples/sample_1/modules/db/db_layer.go
  19. +1 −0 examples/sample_1/modules/gzip/gzip.go
  20. +1 −0 examples/sample_1/modules/headers/headers.go
  21. +25 −13 examples/sample_1/modules/http/http_layer.go
  22. +11 −6 examples/sample_1/modules/logger/logger.go
  23. +2 −4 go.mod
  24. +2 −15 go.sum
  25. +7 −0 go.work
  26. +3 −0 go.work.sum
  27. +13 −0 graph/edge.go
  28. +195 −0 graph/graph.go
  29. +38 −0 graph/toposort.go
  30. +41 −0 graph/vertex.go
  31. +30 −0 graph/weight.go
  32. +157 −0 init.go
  33. +22 −0 options.go
  34. +0 −421 pkg/container/calculate_deps.go
  35. +0 −28 pkg/container/common.go
  36. +0 −31 pkg/container/doc.go
  37. +0 −515 pkg/container/endure.go
  38. +0 −157 pkg/container/init.go
  39. +0 −35 pkg/container/options.go
  40. +0 −60 pkg/container/poller.go
  41. +0 −76 pkg/container/reflect.go
  42. +0 −18 pkg/container/register.go
  43. +0 −66 pkg/container/serve.go
  44. +0 −172 pkg/container/stop.go
  45. +0 −38 pkg/container/visit_collectors.go
  46. +0 −170 pkg/container/visit_providers.go
  47. +0 −229 pkg/fsm/fsm.go
  48. +0 −291 pkg/graph/graph.go
  49. +0 −137 pkg/linked_list/linked_list.go
  50. +0 −190 pkg/vertex/vertex.go
  51. +49 −0 poller.go
  52. +29 −0 registar/entry.go
  53. +17 −0 registar/implements.go
  54. +137 −0 registar/registar.go
  55. +56 −0 serve.go
  56. +57 −0 stop.go
  57. +20 −32 tests/disabled_vertices/disabled_vertices_test.go
  58. +1 −1 tests/disabled_vertices/plugin2/plugin2.go
  59. +2 −9 tests/disabled_vertices/plugin6/plugin6.go
  60. +5 −4 tests/disabled_vertices/plugin7/plugin7.go
  61. +5 −4 tests/disabled_vertices/plugin8/plugin8.go
  62. +4 −2 tests/disabled_vertices/plugin9/plugin9.go
  63. +22 −0 tests/general/test1/p1/pkg/impl.go
  64. +46 −0 tests/general/test1/p1/plugin.go
  65. +52 −0 tests/general/test1/p2/plugin.go
  66. +63 −0 tests/general/test1/p3/plugin.go
  67. +29 −0 tests/general/test1/p4/plugin.go
  68. +22 −0 tests/general/test1/p5/pkg/impl.go
  69. +49 −0 tests/general/test1/p5/plugin.go
  70. +54 −0 tests/general/test1/test1_test.go
  71. +22 −0 tests/general/test2/p1/pkg/impl.go
  72. +46 −0 tests/general/test2/p1/plugin.go
  73. +51 −0 tests/general/test2/p2/plugin.go
  74. +61 −0 tests/general/test2/p3/plugin.go
  75. +29 −0 tests/general/test2/p4/plugin.go
  76. +22 −0 tests/general/test2/p5/pkg/impl.go
  77. +53 −0 tests/general/test2/p5/plugin.go
  78. +33 −0 tests/general/test2/p6/plugin.go
  79. +58 −0 tests/general/test2/test2_test.go
  80. +22 −0 tests/general/test3/p1/pkg/impl.go
  81. +54 −0 tests/general/test3/p1/plugin.go
  82. +43 −0 tests/general/test3/p2/plugin.go
  83. +29 −0 tests/general/test3/test3_test.go
  84. +22 −0 tests/general/test4/p1/pkg/impl.go
  85. +55 −0 tests/general/test4/p1/plugin.go
  86. +44 −0 tests/general/test4/p2/plugin.go
  87. +29 −0 tests/general/test4/test4_test.go
  88. +22 −0 tests/general/test5/p1/pkg/impl.go
  89. +55 −0 tests/general/test5/p1/plugin.go
  90. +46 −0 tests/general/test5/p2/plugin.go
  91. +29 −0 tests/general/test5/test5_test.go
  92. +0 −18 tests/happy_scenarios/README.md
  93. +40 −111 tests/happy_scenarios/happyScenario_test.go
  94. +20 −10 tests/happy_scenarios/plugin1/plugin1.go
  95. +25 −7 tests/happy_scenarios/plugin2/plugin2.go
  96. +19 −10 tests/happy_scenarios/plugin3/plugin3.go
  97. +30 −17 tests/happy_scenarios/plugin4/plugin4.go
  98. +12 −3 tests/happy_scenarios/plugin5/plugin5.go
  99. +11 −3 tests/happy_scenarios/plugin6/plugin6.go
  100. +5 −1 tests/happy_scenarios/plugin7/plugin7.go
  101. +5 −1 tests/happy_scenarios/plugin8/plugin8.go
  102. +9 −3 tests/happy_scenarios/provided_value_but_need_pointer/plugin1/foo2_value.go
  103. +19 −7 tests/happy_scenarios/provided_value_but_need_pointer/plugin2/foo4_value.go
  104. +19 −22 tests/{backoff/backoff_test.go → init/init_test.go}
  105. +2 −1 tests/{backoff → init}/plugins/plugin1/plugin1.go
  106. +5 −2 tests/{backoff → init}/plugins/plugin2/plugin2.go
  107. +2 −1 tests/{backoff → init}/plugins/plugin3/plugin3.go
  108. +2 −1 tests/{backoff → init}/plugins/plugin4/plugin4.go
  109. +5 −1 tests/interfaces/collects/collects_get_all_deps/plugin1.go
  110. +15 −14 tests/interfaces/collects/collects_get_all_deps/plugin2.go
  111. +37 −71 tests/interfaces/interfaces_test.go
  112. +7 −3 tests/interfaces/named/randominterface/plugin1.go
  113. +13 −10 tests/interfaces/named/randominterface/plugin2.go
  114. +7 −4 tests/interfaces/named/registers/plugin1.go
  115. +21 −26 tests/interfaces/named/registers/plugin2.go
  116. +0 −18 tests/interfaces/named/registersfail/plugin1.go
  117. +0 −40 tests/interfaces/named/registersfail/plugin2.go
  118. +7 −3 tests/interfaces/plugins/plugin1/plugin1.go
  119. +5 −2 tests/interfaces/plugins/plugin10/plugin10.go
  120. +11 −3 tests/interfaces/plugins/plugin2/plugin2.go
  121. +5 −2 tests/interfaces/plugins/plugin3/plugin3.go
  122. +5 −2 tests/interfaces/plugins/plugin4/plugin4.go
  123. +9 −9 tests/interfaces/plugins/plugin5/plugin5.go
  124. +28 −19 tests/interfaces/plugins/plugin6/plugin.go
  125. +10 −2 tests/interfaces/plugins/plugin6/plugin2.go
  126. +5 −1 tests/interfaces/plugins/plugin6/plugin3.go
  127. +18 −37 tests/interfaces/plugins/plugin8/plugin8.go
  128. +9 −11 tests/issues/issue33/issue33.go
  129. +5 −1 tests/issues/issue445/plugin1.go
  130. +5 −1 tests/issues/issue445/plugin2.go
  131. +9 −3 tests/issues/issue54/plugin1/plugin1.go
  132. +17 −5 tests/issues/issue54/plugin2/plugin2.go
  133. +34 −23 tests/issues/issue54/plugin3/plugin3.go
  134. BIN tests/issues/issue55/graph.png
  135. +9 −3 tests/issues/issue55/plugin1/plugin1.go
  136. +9 −3 tests/issues/issue55/plugin2/plugin2.go
  137. +7 −1 tests/issues/issue55/plugin3/plugin3.go
  138. +9 −3 tests/issues/issue66/plugin1/plugin1.go
  139. +11 −5 tests/issues/issue66/plugin2/plugin2.go
  140. +23 −6 tests/issues/issue66/plugin3/plugin3.go
  141. +6 −2 tests/issues/issue84/interfaces/plugin1/plugin1.go
  142. +4 −2 tests/issues/issue84/interfaces/plugin2/plugin2.go
  143. +6 −2 tests/issues/issue84/interfaces/plugin3/plugin3.go
  144. +6 −2 tests/issues/issue84/interfaces_structs/plugin1/plugin1.go
  145. +4 −2 tests/issues/issue84/interfaces_structs/plugin2/plugin2.go
  146. +6 −2 tests/issues/issue84/interfaces_structs/plugin3/plugin3.go
  147. +7 −3 tests/issues/issue84/one_alive/plugin1/plugin1.go
  148. +12 −3 tests/issues/issue84/one_alive/plugin2/plugin2.go
  149. +7 −1 tests/issues/issue84/one_alive/plugin3/plugin3.go
  150. +6 −2 tests/issues/issue84/structs/plugin1/plugin1.go
  151. +4 −2 tests/issues/issue84/structs/plugin2/plugin2.go
  152. +6 −2 tests/issues/issue84/structs/plugin3/plugin3.go
  153. +66 −73 tests/issues/issues_test.go
  154. +0 −5 tests/stress/CollectorFuncReturn/CyclicDepsCollectsInit/api/p1/interface.go
  155. +0 −5 tests/stress/CollectorFuncReturn/CyclicDepsCollectsInit/api/p2/interface.go
  156. +13 −9 tests/stress/CollectorFuncReturn/CyclicDepsCollectsInit/p1/plugin1.go
  157. +13 −9 tests/stress/CollectorFuncReturn/CyclicDepsCollectsInit/p2/plugin2.go
  158. +0 −47 tests/stress/CollectorFuncReturn/foo.go
  159. +5 −1 tests/stress/CyclicDeps/plugin1.go
  160. +5 −1 tests/stress/CyclicDeps/plugin2.go
  161. +5 −1 tests/stress/CyclicDeps/plugin3.go
  162. +0 −5 tests/stress/CyclicDepsCollects/api/p1/interface.go
  163. +0 −5 tests/stress/CyclicDepsCollects/api/p2/interface.go
  164. +13 −9 tests/stress/CyclicDepsCollects/p1/plugin1.go
  165. +13 −9 tests/stress/CyclicDepsCollects/p2/plugin2.go
  166. +0 −5 tests/stress/CyclicDepsCollectsInit/api/p1/interface.go
  167. +0 −5 tests/stress/CyclicDepsCollectsInit/api/p2/interface.go
  168. +7 −3 tests/stress/CyclicDepsCollectsInit/p1/plugin1.go
  169. +7 −3 tests/stress/CyclicDepsCollectsInit/p2/plugin2.go
  170. +2 −1 tests/stress/InitErr/foo1_init_err.go
  171. +5 −1 tests/stress/InitErr/foo2_init_err.go
  172. +3 −2 tests/stress/ServeErr/foo1_serve_error.go
  173. +13 −9 tests/stress/ServeErr/foo3_serve_error.go
  174. +25 −8 tests/stress/ServeErr/foo4ServeError.go
  175. +21 −9 tests/stress/ServeErr/plugin2.go
  176. +7 −1 tests/stress/ServeErr/plugin5.go
  177. +0 −30 tests/stress/ServeRetryErr/plugin1.go
  178. +0 −20 tests/stress/ServeRetryErr/plugin2.go
  179. +0 −66 tests/stress/ServeRetryErr/plugin3.go
  180. +0 −18 tests/stress/ServeRetryErr/plugin4.go
  181. +0 −22 tests/stress/ServeRetryErr/plugin5.go
  182. +0 −35 tests/stress/ServeRetryErr/plugin6.go
  183. +13 −3 tests/stress/mixed/foo.go
  184. +26 −179 tests/stress/stress_test.go
  185. +0 −13 {pkg/container → }/utils.go
  186. +7 −39 {pkg/container → }/visualize.go
2 changes: 1 addition & 1 deletion .github/workflows/linux.yml
Original file line number Diff line number Diff line change
@@ -45,7 +45,7 @@ jobs:
- name: Run golang tests on ${{ matrix.os }}
run: |
mkdir ./coverage-ci
go test -v -race -cover -tags=debug -coverpkg=./... -coverprofile=./coverage-ci/backoff.txt -covermode=atomic ./tests/backoff
go test -v -race -cover -tags=debug -coverpkg=./... -coverprofile=./coverage-ci/backoff.txt -covermode=atomic ./tests/init
go test -v -race -cover -tags=debug -coverpkg=./... -coverprofile=./coverage-ci/happy_scenarios.txt -covermode=atomic ./tests/happy_scenarios
go test -v -race -cover -tags=debug -coverpkg=./... -coverprofile=./coverage-ci/interfaces.txt -covermode=atomic ./tests/interfaces
go test -v -race -cover -tags=debug -coverpkg=./... -coverprofile=./coverage-ci/issues.txt -covermode=atomic ./tests/issues
2 changes: 1 addition & 1 deletion .github/workflows/macOS.yml
Original file line number Diff line number Diff line change
@@ -44,7 +44,7 @@ jobs:

- name: Run golang tests on ${{ matrix.os }}
run: |
go test -v -race -cover -tags=debug ./tests/backoff
go test -v -race -cover -tags=debug ./tests/init
go test -v -race -cover -tags=debug ./tests/happy_scenarios
go test -v -race -cover -tags=debug ./tests/interfaces
go test -v -race -cover -tags=debug ./tests/issues
2 changes: 1 addition & 1 deletion .github/workflows/windows.yml
Original file line number Diff line number Diff line change
@@ -44,7 +44,7 @@ jobs:

- name: Run golang tests on ${{ matrix.os }}
run: |
go test -v -race -tags=debug ./tests/backoff
go test -v -race -tags=debug ./tests/init
go test -v -race -tags=debug ./tests/happy_scenarios
go test -v -race -tags=debug ./tests/interfaces
go test -v -race -tags=debug ./tests/issues
7 changes: 6 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
test:
go test -v -race -tags=debug ./tests/backoff
go test -v -race -tags=debug ./tests/general/test1
go test -v -race -tags=debug ./tests/general/test2
go test -v -race -tags=debug ./tests/general/test3
go test -v -race -tags=debug ./tests/general/test4
go test -v -race -tags=debug ./tests/general/test5
go test -v -race -tags=debug ./tests/init
go test -v -race -tags=debug ./tests/happy_scenarios
go test -v -race -tags=debug ./tests/interfaces
go test -v -race -tags=debug ./tests/issues
143 changes: 64 additions & 79 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,71 +1,69 @@
# Endure

<p align="center">
<a href="https://pkg.go.dev/github.com/roadrunner-server/endure?tab=doc"><img src="https://godoc.org/github.com/roadrunner-server/endure?status.svg"></a>
<a href="https://pkg.go.dev/github.com/roadrunner-server/endure/v2?tab=doc"><img src="https://godoc.org/github.com/roadrunner-server/endure/v2?status.svg"></a>
<a href="https://github.com/roadrunner-server/endure/actions"><img src="https://github.com/roadrunner-server/endure/workflows/Linux/badge.svg" alt=""></a>
<a href="https://github.com/roadrunner-server/endure/actions"><img src="https://github.com/roadrunner-server/endure/workflows/macOS/badge.svg" alt=""></a>
<a href="https://github.com/roadrunner-server/endure/actions"><img src="https://github.com/roadrunner-server/endure/workflows/Windows/badge.svg" alt=""></a>
<a href="https://github.com/roadrunner-server/endure/actions"><img src="https://github.com/roadrunner-server/endure/workflows/Linters/badge.svg" alt=""></a>
<a href="https://codecov.io/gh/roadrunner-server/endure"><img src="https://codecov.io/gh/roadrunner-server/endure/branch/master/graph/badge.svg?token=itNaiZ6ALN"/></a>
<a href="https://discord.gg/TFeEmCs"><img src="https://img.shields.io/badge/discord-chat-magenta.svg"></a>
<a href="https://lgtm.com/projects/g/roadrunner-server/endure/alerts/"><img src="https://img.shields.io/lgtm/alerts/g/roadrunner-server/endure.svg?logo=lgtm&logoWidth=18"></a>
</p>

Endure is an open-source (MIT licensed) plugin container with IoC and self-healing.
Endure is an open-source (MIT licensed) plugin container with IoC (Inversion of Control) and self-healing capabilities.

<h2>Features</h2>
## Features

- Supports structs and interfaces (see examples)
- Use graph to topologically sort, run, stop and restart dependent plugins
- Algorithms used: graph and double-linked list
- Support easy to add Middleware plugins
- Supports interfaces (see examples)
- Uses a graph to topologically sort, run, stop, and restart dependent plugins
- Supports easy addition of Middleware plugins
- Error reporting

<h2>Installation</h2>
## Installation

```go
go get -u github.com/roadrunner-server/endure
go get -u github.com/roadrunner-server/endure/v2
```


### Why?

Imagine you have an application in which you want to implement plugin system. These plugins can depend on each other (
via interfaces or directly). For example, we have 3 plugins: HTTP (to communicate with world), DB (to save the world)
and logger (to see the progress).
In this particular case, we can't start HTTP before we start all other parts. Also, we have to initialize logger first,
because all parts of our system need logger. All you need to do in `Endure` is to pass `HTTP`, `DB` and `Logger` structs
to the `Endure` and implement `Endure` interface. So, the dependency graph will be the following:
Imagine you have an application in which you want to implement a plugin system. These plugins can depend on each other (via interfaces or directly). For example, we have 3 plugins: HTTP (to communicate with the world), DB (to save the world), and logger (to see the progress). In this particular case, we can't start HTTP before we start all other parts. Also, we have to initialize the logger first, because all parts of our system need the logger. All you need to do in Endure is to pass the `HTTP`, `DB`, and `Logger` structs to Endure and implement the `Endure` interface. So, the dependency graph will be the following:

<p align="left">
<img src="https://github.com/roadrunner-server/endure/blob/master/images/graph.png" width="300" height="250" />
</p>
![Dependency Graph](https://github.com/roadrunner-server/endure/blob/master/images/graph.png)

-------
First step is to initialize the `endure` container:
First, we initialize the `endure` container:

```go
container, err := endure.NewContainer(nil, endure.SetLogLevel(endure.ErrorLevel), endure.Visualize(endure.StdOut, ""))
import (
"golang.org/x/exp/slog"
)

func main() {
container := endure.New(slog.LevelDebug, endure.Visualize())
}
```

Let's take a look at the `endure.NewContainer()`:
Let's take a look at the `endure.New()` function:

1. The first argument is the standard golang logger log level.
2. The next arguments are optional and can be set using `Options`. For example, `endure.Visualize()` will show you a dot-compatible graph in the console. Then we need to pass our structures as references to the `RegisterAll` or `Register` function.

1. First arg here is the external logger. If you want to use your own logger, you can pass it as the first argument.
2. Next arguments are optional and can be set using `Options`. For example `endure.Visualize(endure.StdOut, "")` will
show you dot-compatible graph in the console.
Then we need to pass our structures as references to the `RegisterAll` or `Register` function.

```go
err = container.RegisterAll(
&httpPlugin{},
&DBPlugin{},
&LoggerPlugin{})
&LoggerPlugin{},
)
if err != nil {
panic(err)
}
}
```

The order of plugins in the `RegisterAll` plugin does no matter.
Next we need to initialize and run our container:
The order of plugins in the `RegisterAll` function does not matter.
Next, we need to initialize and run our container:


```go
err := container.Init()
@@ -78,8 +76,8 @@ errCh, err := container.Serve()
}
```

`errCh` is the channel with errors from the all `Vertices`. You can identify vertex by `vertexID` which is presented
in `errCh` struct. Then just process the events from the `errCh`:

`errCh` is the channel with errors from all `Vertices`. You can identify the vertex by `vertexID`, which is presented in the `errCh` struct. Then just process the events from the `errCh`:

```go
for {
@@ -95,70 +93,57 @@ for {
}
```

Also `Endure` will take care of the restart failing vertices (HTTP, DB, Logger in example) with exponential backoff
mechanism.
The start will proceed in topological order (`Logger` -> `DB` -> `HTTP`), and the stop in reverse-topological order
automatically.
The start will proceed in topological order (Logger -> DB -> HTTP), and the stop in reverse-topological order automatically.

<h2>Endure main interface</h2>
### Endure main interface

```go
package sample

import (
"github.com/roadrunner-server/endure/v2/dep"
)

type (
// This is the main Endure service interface which may be implemented to Start (Serve) and Stop plugin (OPTIONAL)
Service interface {
// Serve
Serve() chan error
// Stop
Stop() error
}

// Name of the service (OPTIONAL)
Named interface {
Name() string
}

// Provider declares the ability to provide dependencies to other plugins (OPTIONAL)
Provider interface {
Provides() []any
}

// Collector declares the ability to accept the plugins which match the provided method signature (OPTIONAL)
Collector interface {
Collects() []any
}
// This is the main Endure service interface which may be implemented to Start (Serve) and Stop plugin (OPTIONAL)
Service interface {
// Serve
Serve() chan error
// Stop with context, if you reach the timeout, endure will force the exit via context deadline
Stop(context.Context) error
// Named return plugin's name
Named() string
}

// Provider declares the ability to provide dependencies to other plugins (OPTIONAL)
Provider interface {
Provides() []*dep.In
}

// Collector declares the ability to accept the plugins which match the provided method signature (OPTIONAL)
Collector interface {
Collects() []*dep.Out
}
)

// Init is mandatory to implement
type Plugin struct{}

func (p *Plugin) Init( /* deps here */) error {
return nil
return nil
}
```

Order is the following:

1. `Init() error` - is mandatory to implement. For your structure (which you pass to `Endure`), you should have this method as the method of the struct(```go func (p *Plugin) Init() error {}```). It can accept as a parameter any passed to the `Endure` structure (see samples) or interface (with
limitations).
2. `Service` - is optional to implement. It has 2 methods - `Serve` which should run the plugin and return
initialized golang channel with errors, and `Stop` to shut down the plugin. The `Stop` and `Serve` should not block the execution.
1. `Init() error` - is mandatory to implement. For your structure (which you pass to `Endure`), you should have this method as the method of the struct (```go func (p *Plugin) Init() error {}```). It can accept as a parameter any passed to the `Endure` structure (see samples) or interface (with limitations).
2. `Service` - is optional to implement. It has 2 methods: `Serve` which should run the plugin and return an initialized golang channel with errors, and `Stop` to shut down the plugin. The `Stop` and `Serve` should not block the execution.
3. `Provider` - is optional to implement. It is used to provide some dependency if you need to extend your struct without deep modification.
4. `Collector` - is optional to implement. It is used to mark a structure (vertex) as some struct dependency. It can
accept interfaces which implement a caller.
5. `Named` - is mandatory to implement. This is a special kind of interface which provides the name of the struct (
plugin, vertex) to the caller. Is useful in logger (for example) to know user-friendly plugin name.
4. `Collector` - is optional to implement. It is used to mark a structure (vertex) as some struct dependency. It can accept interfaces that implement a caller.
5. `Named` - is mandatory to implement. This is a special kind of interface that provides the name of the struct (plugin, vertex) to the caller. It is useful in the logger (for example) to know the user-friendly plugin name.

Available options:
1. `SetLogLevel` - used to set internal log level. Available options: `endure.DebugLevel`, `endure.InfoLevel`,`endure.WarnLevel`,`endure.ErrorLevel`,`endure.DPanicLevel`,`endure.PanicLevel`,`endure.FatalLevel` ordered from the most to the least verbosity level.
2. `RetryOnFail`: bool, used to reinitialize graph w/o stopping application when error received from the `Serve`.
3. `SetBackoff`: initialInterval, maxInterval, `time.Duration`. When `RetryOnFail` is set, backoff configures how much time spend to reinitialize vertex.
4. `Visualize`: Output (`endure.StdOut`, `endure.File`), path. Graph visualization option via the graphviz. The Graphviz diagram can be shown via stdout or file (path should not be empty).
5. `GracefulShutdownTimeout`: time.Duration. How long to wait for a vertex (plugin) to stop.

The fully operational example located in the `examples` folder.
1. `Visualize`: Graph visualization option via graphviz. The Graphviz diagram can be shown via stdout.
2. `GracefulShutdownTimeout`: `time.Duration`. How long to wait for a vertex (plugin) to stop.

## Known issues:
- [ ] Vertex can provide only 1 implementaion per interface. For example, at the moment, you can't provide two implementations of the `Logger` interface within the same vertex.
- [ ] No support for the type aliases.
The fully operational example is located in the `examples` folder.
42 changes: 42 additions & 0 deletions collects.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package endure

import (
"github.com/roadrunner-server/errors"
)

func (e *Endure) collects() error {
vertices := e.graph.TopologicalOrder()

for i := 0; i < len(vertices); i++ {
if !vertices[i].IsActive() {
continue
}

if _, ok := vertices[i].Plugin().(Collector); !ok {
continue
}

// in deps
collects := vertices[i].Plugin().(Collector).Collects()

// get vals
for j := 0; j < len(collects); j++ {
impl := e.registar.ImplementsExcept(collects[j].Type, vertices[i].Plugin())
if len(impl) == 0 {
continue
}

for k := 0; k < len(impl); k++ {
value, ok := e.registar.TypeValue(impl[k].Plugin(), collects[j].Type)
if !ok {
return errors.E("this is likely a bug, nil value from the implements. Value should be initialized due to the topological order")
}

// call user's callback
collects[j].Callback(value.Interface())
}
}
}

return nil
}
33 changes: 23 additions & 10 deletions pkg/container/container.go → container.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
package endure

// InitMethodName is the function fn for the reflection
const InitMethodName = "Init"
import (
"context"

// ServeMethodName is the function fn for the Serve
const ServeMethodName = "Serve"
"github.com/roadrunner-server/endure/v2/dep"
)

// StopMethodName is the function fn for the reflection to Stop the service
const StopMethodName = "Stop"
const (
// InitMethodName is the function fn for the reflection
InitMethodName = "Init"
// ServeMethodName is the function fn for the Serve
ServeMethodName = "Serve"
// StopMethodName is the function fn for the reflection to Stop the service
StopMethodName = "Stop"
)

// Result is the information which endure sends to the user
type Result struct {
@@ -34,7 +40,7 @@ type (
// Serve starts the plugin
Serve() chan error
// Stop stops the plugin
Stop() error
Stop(context.Context) error
}

// Named -> Name of the service
@@ -51,6 +57,8 @@ type (
Stop() error
// Register registers one plugin in container
Register(service any) error
// Plugins method is responsible for returning an all registered plugins
Plugins() string
// RegisterAll register set of comma separated plugins in container
RegisterAll(service ...any) error
// Init initializes all plugins (calling Init function), calculate vertices, invoke Collects and Provided functions if exist
@@ -60,12 +68,17 @@ type (
// Provider declares the ability to provide service edges of declared types.
Provider interface {
// Provides function return set of functions which provided dependencies to other plugins
Provides() []any
Provides() []*dep.Out
}

// Weighted is optional to implement, but when implemented the return value added during the topological sort
Weighted interface {
Weight() uint
}

// Collector declares the ability to accept the plugins which match the provided method signature.
Collector interface {
// Collects search for the structures or (and) interfaces in the arguments and provides it for the plugin
Collects() []any
// Collects search for the plugins which implements given interfaces in the args
Collects() []*dep.In
}
)
25 changes: 25 additions & 0 deletions dep/in.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package dep

import (
"reflect"
)

type In struct {
Type reflect.Type
Callback func(any)
}

func Fits(callback func(p any), tp any) *In {
if reflect.TypeOf(tp) == nil {
panic("nil type provided, should be of the form of: (*FooBar)(nil), not (FooBar)(nil)")
}

if reflect.TypeOf(tp).Elem().Kind() != reflect.Interface {
panic("type should be of the Interface type")
}

return &In{
Type: reflect.TypeOf(tp).Elem(),
Callback: callback,
}
}
Loading