Repository: kestra-io/kestra
Issue: Deprecate listeners in favor of triggers

### Feature description

this pattern will be deprecated:

```yaml
id: slackFailureNotifications
namespace: prod
tasks:
  - id: fail
    type: io.kestra.core.tasks.scripts.Bash
    commands:
      - exit 1
listeners:
  - conditions:
      - type: io.kestra.core.models.conditions.types.ExecutionStatusCondition
        in:
          - FAILED
    tasks:
      - id: slack
        type: io.kestra.plugin.notifications.slack.SlackExecution
        url: {{envs.slack_webhook}}
        channel: "#general"
```

in favor of triggers:
```yaml
id: slack-global
namespace: com.kestra.monitoring

tasks:
  - id: send
    type: io.kestra.plugin.notifications.slack.SlackExecution
    url: "{{ namespace.slack.webhook }}"
    channel: "C02U601DNAJ"
    username: "Kestra"
    iconEmoji: ":kestra:"
    executionId: "{{ trigger.executionId }}"

triggers:
  - id: listen
    type: io.kestra.core.models.triggers.types.Flow
    conditions:
      - type: io.kestra.core.models.conditions.types.ExecutionStatusCondition
        in:
          - FAILED
          - WARNING
      - type: io.kestra.core.models.conditions.types.ExecutionNamespaceCondition
        namespace: com.kestra
        prefix: true
```

cc @Ben8t backlog

Issue comments:
related to #1713 
acc to @Skraye and @Ben8t, listeners can be used for lineage to avoid an extra flow, they will be added to the topology
Keeping the debat open for the following reasons : 

- creating an external flow (with trigger) to resolve failure notification seems a bit overwhelming 🤔 
- the concept of listeners could be used for #1246 (+ see this [Notion page](https://www.notion.so/kestra-io/SLA-Freshness-Timeout-0cf7cf6bf89e42eaa453de0bc4966591?pvs=4)), especially for running tasks after the main flow execution.
- the concept of listeners could be used for metadata management, for example "when the flow finished with success then upload this metadata to an external system (data lineage/catalog tools for example), expose metadata in Kestra, etc."
1. why overwhelming? you need to define it usually once for the entire namespace, otherwise you can just use the `errors`
2. SLA is also listening to some conditions the same way as triggers which are more flexible and decoupled than listeners 
3. for metadata management, it would be especially useful to define it once on a namespace level with a trigger than adding boilerplate listeners to each flow only to collect metadata 

maybe the issue you see is that the trigger dependencies are not displayed directly in the same DAG view? if so, maybe better to postpone this discussion until the topology redesign is done? with triggers being displayed faster/better, there is no need for listeners (of which the only benefit is being coupled to a flow rather than decoupled)
Yes my main doubt is about having one main flow where you have usual tasks, and then have to create another flow with triggers where you put your "SLA", "Trigger/Freshness" conditions. Uncoupled, but for what purpose ? It also makes sense to have them close the actual flow.

With SLA ~ listeners we don't have this "listening/polling pattern" consuming ressources (actually a better wording would be something like "afterExecution"), i.e. when the flow has finished to run do X/expose SLA values in the data model/dashboard.

Feeling like the debate Trigger vs Listeners is like the Push (listeners) vs Pull (trigger) pattern - both are good depending of the context, but I might be wrong 🤔 

On 1., I agree `errors` do the work, but isn't it just a specific type of "listeners" 🤔 ? What about "my flow is in WARNING", "this task metric value is equal to X", etc... worth considering this as a whole maybe

For metadata I agree too, we might have a better space than Flow for this 🤔 (that's another discussion 😅)
afterExecution is equivalent to adding one more downstream task

if you have more nuanced conditions, that's what triggers are for
@brian-mulier-p can you add annotation to the UI to show that Listeners are deprecated?
> @brian-mulier-p can you add annotation to the UI to show that Listeners are deprecated?

Sure
done in #2020 

Pull request review comments:

Patch that resolved the issue:
diff --git a/core/src/main/java/io/kestra/core/models/flows/Flow.java b/core/src/main/java/io/kestra/core/models/flows/Flow.java
index bde1b57026..dc57407abc 100644
--- a/core/src/main/java/io/kestra/core/models/flows/Flow.java
+++ b/core/src/main/java/io/kestra/core/models/flows/Flow.java
@@ -86,6 +86,7 @@ public boolean hasIgnoreMarker(final AnnotatedMember m) {
     List<Task> errors;
 
     @Valid
+    @Deprecated
     List<Listener> listeners;
 
     @Valid
diff --git a/core/src/main/java/io/kestra/core/services/FlowService.java b/core/src/main/java/io/kestra/core/services/FlowService.java
index f2ed1f97e1..7ce8be4e21 100644
--- a/core/src/main/java/io/kestra/core/services/FlowService.java
+++ b/core/src/main/java/io/kestra/core/services/FlowService.java
@@ -72,7 +72,7 @@ private Stream<String> deprecationTraversal(String prefix, Object object) {
                         }
 
                         return Stream.concat(
-                            method.isAnnotationPresent(Deprecated.class) && fieldValue != null ? Stream.of(prefix + "." + fieldName) : Stream.empty(),
+                            method.isAnnotationPresent(Deprecated.class) && fieldValue != null ? Stream.of(prefix.isEmpty() ? fieldName : prefix + "." + fieldName) : Stream.empty(),
                             additionalDeprecationPaths
                         );
                     } catch (IllegalAccessException | InvocationTargetException e) {


Test patch:
diff --git a/webserver/src/test/java/io/kestra/webserver/controllers/FlowControllerTest.java b/webserver/src/test/java/io/kestra/webserver/controllers/FlowControllerTest.java
index 44116136ba..40b9b336f7 100644
--- a/webserver/src/test/java/io/kestra/webserver/controllers/FlowControllerTest.java
+++ b/webserver/src/test/java/io/kestra/webserver/controllers/FlowControllerTest.java
@@ -669,8 +669,8 @@ void validateFlows() throws IOException {
 
         List<ValidateConstraintViolation> body = response.body();
         assertThat(body.size(), is(2));
-        assertThat(body.get(0).getDeprecationPaths(), hasSize(2));
-        assertThat(body.get(0).getDeprecationPaths(), containsInAnyOrder("tasks[1]", "tasks[1].additionalProperty"));
+        assertThat(body.get(0).getDeprecationPaths(), hasSize(3));
+        assertThat(body.get(0).getDeprecationPaths(), containsInAnyOrder("tasks[1]", "tasks[1].additionalProperty", "listeners"));
         assertThat(body.get(1).getDeprecationPaths(), empty());
         assertThat(body, everyItem(
             Matchers.hasProperty("constraints", is(nullValue()))
diff --git a/webserver/src/test/resources/flows/validateMultipleValidFlows.yaml b/webserver/src/test/resources/flows/validateMultipleValidFlows.yaml
index 7918ca47c2..50980dd1cb 100644
--- a/webserver/src/test/resources/flows/validateMultipleValidFlows.yaml
+++ b/webserver/src/test/resources/flows/validateMultipleValidFlows.yaml
@@ -7,6 +7,11 @@ tasks:
   - id: deprecated_task
     type: io.kestra.core.plugins.test.DeprecatedTask
     additionalProperty: "value"
+listeners:
+  - tasks:
+      - id: log
+        type: io.kestra.core.tasks.log.Log
+        message: logging
 
 ---