@@ -6,11 +6,15 @@ import (
6
6
"encoding/hex"
7
7
"errors"
8
8
"fmt"
9
+ "strconv"
9
10
"sync"
10
11
"time"
11
12
12
13
"github.com/jonboulle/clockwork"
14
+ "google.golang.org/protobuf/proto"
13
15
16
+ "github.com/smartcontractkit/chainlink-common/pkg/aggregation"
17
+ "github.com/smartcontractkit/chainlink-common/pkg/beholder"
14
18
"github.com/smartcontractkit/chainlink-common/pkg/capabilities"
15
19
"github.com/smartcontractkit/chainlink-common/pkg/custmsg"
16
20
"github.com/smartcontractkit/chainlink-common/pkg/metrics"
@@ -20,10 +24,10 @@ import (
20
24
"github.com/smartcontractkit/chainlink-common/pkg/workflows"
21
25
"github.com/smartcontractkit/chainlink-common/pkg/workflows/exec"
22
26
"github.com/smartcontractkit/chainlink-common/pkg/workflows/sdk"
23
-
24
27
"github.com/smartcontractkit/chainlink/v2/core/capabilities/transmission"
25
28
"github.com/smartcontractkit/chainlink/v2/core/logger"
26
29
"github.com/smartcontractkit/chainlink/v2/core/platform"
30
+ "github.com/smartcontractkit/chainlink/v2/core/services/workflows/pb"
27
31
"github.com/smartcontractkit/chainlink/v2/core/services/workflows/ratelimiter"
28
32
"github.com/smartcontractkit/chainlink/v2/core/services/workflows/store"
29
33
"github.com/smartcontractkit/chainlink/v2/core/services/workflows/syncerlimiter"
@@ -502,9 +506,14 @@ func generateExecutionID(workflowID, eventID string) (string, error) {
502
506
}
503
507
504
508
// startExecution kicks off a new workflow execution when a trigger event is received.
505
- func (e * Engine ) startExecution (ctx context.Context , executionID string , event * values.Map ) error {
509
+ func (e * Engine ) startExecution (ctx context.Context , executionID string , triggerID string , event * values.Map ) error {
506
510
e .meterReports .Add (executionID , NewMeteringReport ())
507
511
512
+ err := emitExecutionStartedEvent (ctx , e .cma , triggerID )
513
+ if err != nil {
514
+ e .logger .Errorf ("failed to emit execution started event: %+v" , err )
515
+ }
516
+
508
517
lggr := e .logger .With ("event" , event , platform .KeyWorkflowExecutionID , executionID )
509
518
lggr .Debug ("executing on a trigger event" )
510
519
workflowExecution , err := e .executionsStore .Add (ctx , map [string ]* store.WorkflowExecutionStep {
@@ -676,6 +685,10 @@ func (e *Engine) finishExecution(ctx context.Context, cma custmsg.MessageEmitter
676
685
}
677
686
logCustMsg (ctx , cma , fmt .Sprintf ("execution duration: %d (seconds)" , executionDuration ), l )
678
687
l .Infof ("execution duration: %d (seconds)" , executionDuration )
688
+ err = emitExecutionFinishedEvent (ctx , cma , status )
689
+ if err != nil {
690
+ e .logger .Errorf ("failed to emit execution finished event: %+v" , err )
691
+ }
679
692
e .onExecutionFinished (executionID )
680
693
return nil
681
694
}
@@ -731,7 +744,7 @@ func (e *Engine) worker(ctx context.Context) {
731
744
}
732
745
733
746
cma := e .cma .With (platform .KeyWorkflowExecutionID , executionID )
734
- err = e .startExecution (ctx , executionID , resp .Event .Outputs )
747
+ err = e .startExecution (ctx , executionID , te . ID , resp .Event .Outputs )
735
748
if err != nil {
736
749
e .logger .With (platform .KeyWorkflowExecutionID , executionID ).Errorf ("failed to start execution: %v" , err )
737
750
logCustMsg (ctx , cma , fmt .Sprintf ("failed to start execution: %s" , err ), e .logger )
@@ -997,13 +1010,32 @@ func (e *Engine) executeStep(ctx context.Context, lggr logger.Logger, msg stepRe
997
1010
defer cancel ()
998
1011
999
1012
e .metrics .with (platform .KeyCapabilityID , curStep .ID ).incrementCapabilityInvocationCounter (ctx )
1000
- output , err := curStep .capability . Execute ( stepCtx , tr )
1013
+ err = emitCapabilityStartedEvent ( ctx , e . cma , curStep .ID , msg . stepRef )
1001
1014
if err != nil {
1015
+ e .logger .Errorf ("failed to emit capability event: %v" , err )
1016
+ }
1017
+ output , capErr := curStep .capability .Execute (stepCtx , tr )
1018
+ status := store .StatusCompleted
1019
+
1020
+ if capErr != nil {
1021
+ status = store .StatusErrored
1022
+ if capabilities .ErrStopExecution .Is (capErr ) {
1023
+ status = store .StatusCompletedEarlyExit
1024
+ }
1025
+ }
1026
+
1027
+ defer func () {
1028
+ if err := emitCapabilityFinishedEvent (ctx , e .cma , curStep .ID , msg .stepRef , status ); err != nil {
1029
+ e .logger .Errorf ("failed to emit capability event: %v" , err )
1030
+ }
1031
+ }()
1032
+
1033
+ if capErr != nil {
1002
1034
e .metrics .with (platform .KeyStepRef , msg .stepRef , platform .KeyCapabilityID , curStep .ID ).incrementCapabilityFailureCounter (ctx )
1003
- return inputsMap , capabilities.CapabilityResponse {}, err
1035
+ return inputsMap , capabilities.CapabilityResponse {}, capErr
1004
1036
}
1005
1037
1006
- return inputsMap , output , err
1038
+ return inputsMap , output , nil
1007
1039
}
1008
1040
1009
1041
func (e * Engine ) deregisterTrigger (ctx context.Context , t * triggerCapability , triggerIdx int ) error {
@@ -1355,7 +1387,22 @@ func NewEngine(ctx context.Context, cfg Config) (engine *Engine, err error) {
1355
1387
return nil , fmt .Errorf ("could not initialize monitoring resources: %w" , err )
1356
1388
}
1357
1389
1358
- cma := custmsg .NewLabeler ().With (platform .KeyWorkflowID , cfg .WorkflowID , platform .KeyWorkflowOwner , cfg .WorkflowOwner , platform .KeyWorkflowName , cfg .WorkflowName .String ())
1390
+ nodeState , err := cfg .Registry .LocalNode (ctx )
1391
+ if err != nil {
1392
+ return nil , fmt .Errorf ("could not get local node state: %w" , err )
1393
+ }
1394
+ cma := custmsg .NewLabeler ().With (platform .KeyWorkflowID , cfg .WorkflowID ,
1395
+ platform .KeyWorkflowOwner , cfg .WorkflowOwner ,
1396
+ platform .KeyWorkflowName , cfg .WorkflowName .String (),
1397
+ platform .KeyDonID , strconv .Itoa (int (nodeState .WorkflowDON .ID )),
1398
+ platform .KeyDonF , strconv .Itoa (int (nodeState .WorkflowDON .F )),
1399
+ platform .KeyDonN , strconv .Itoa (len (nodeState .WorkflowDON .Members )),
1400
+ platform .KeyDonQ , strconv .Itoa (aggregation .ByzantineQuorum (
1401
+ len (nodeState .WorkflowDON .Members ),
1402
+ int (nodeState .WorkflowDON .F ),
1403
+ )),
1404
+ platform .KeyP2PID , nodeState .PeerID .String (),
1405
+ )
1359
1406
workflow , err := Parse (cfg .Workflow )
1360
1407
if err != nil {
1361
1408
logCustMsg (ctx , cma , fmt .Sprintf ("failed to parse workflow: %s" , err ), cfg .Lggr )
@@ -1440,3 +1487,125 @@ func logCustMsg(ctx context.Context, cma custmsg.MessageEmitter, msg string, log
1440
1487
log .Errorf ("failed to send custom message with msg: %s, err: %v" , msg , err )
1441
1488
}
1442
1489
}
1490
+
1491
+ // buildWorkflowMetadata populates a WorkflowMetadata from kvs (map[string]string).
1492
+ func buildWorkflowMetadata (kvs map [string ]string ) * pb.WorkflowMetadata {
1493
+ m := & pb.WorkflowMetadata {}
1494
+
1495
+ m .WorkflowName = kvs [platform .KeyWorkflowName ]
1496
+ m .Version = kvs [platform .KeyWorkflowVersion ]
1497
+ m .WorkflowID = kvs [platform .KeyWorkflowID ]
1498
+ m .WorkflowExecutionID = kvs [platform .KeyWorkflowExecutionID ]
1499
+
1500
+ if donIDStr , ok := kvs [platform .KeyDonID ]; ok {
1501
+ if id , err := strconv .ParseInt (donIDStr , 10 , 32 ); err == nil {
1502
+ m .DonF = int32 (id )
1503
+ }
1504
+ }
1505
+
1506
+ m .P2PID = kvs [platform .KeyP2PID ]
1507
+
1508
+ if donFStr , ok := kvs [platform .KeyDonF ]; ok {
1509
+ if id , err := strconv .ParseInt (donFStr , 10 , 32 ); err == nil {
1510
+ m .DonF = int32 (id )
1511
+ }
1512
+ }
1513
+ if donNStr , ok := kvs [platform .KeyDonN ]; ok {
1514
+ if id , err := strconv .ParseInt (donNStr , 10 , 32 ); err == nil {
1515
+ m .DonN = int32 (id )
1516
+ }
1517
+ }
1518
+ if donQStr , ok := kvs [platform .KeyDonQ ]; ok {
1519
+ if id , err := strconv .ParseInt (donQStr , 10 , 32 ); err == nil {
1520
+ m .DonQ = int32 (id )
1521
+ }
1522
+ }
1523
+
1524
+ return m
1525
+ }
1526
+
1527
+ // emitProtoMessage marshals a proto.Message and emits it via beholder.
1528
+ func emitProtoMessage (ctx context.Context , msg proto.Message ) error {
1529
+ b , err := proto .Marshal (msg )
1530
+ if err != nil {
1531
+ return err
1532
+ }
1533
+
1534
+ // Determine the schema and entity based on the message type
1535
+ var schema , entity string
1536
+ switch msg .(type ) {
1537
+ case * pb.WorkflowExecutionStarted :
1538
+ schema = SchemaWorkflowStarted
1539
+ entity = EventWorkflowExecutionStarted
1540
+ case * pb.WorkflowExecutionFinished :
1541
+ schema = SchemaWorkflowFinished
1542
+ entity = EventWorkflowExecutionFinished
1543
+ case * pb.CapabilityExecutionStarted :
1544
+ schema = SchemaCapabilityStarted
1545
+ entity = EventCapabilityExecutionStarted
1546
+ case * pb.CapabilityExecutionFinished :
1547
+ schema = SchemaCapabilityFinished
1548
+ entity = EventCapabilityExecutionFinished
1549
+ default :
1550
+ return fmt .Errorf ("unknown message type: %T" , msg )
1551
+ }
1552
+
1553
+ // entity must be prefixed with the proto package name
1554
+ entity = fmt .Sprintf ("%s.%s" , EventsProtoPkg , entity )
1555
+
1556
+ return beholder .GetEmitter ().Emit (ctx , b ,
1557
+ "beholder_data_schema" , schema , // required
1558
+ "beholder_domain" , "platform" , // required
1559
+ "beholder_entity" , entity ) // required
1560
+ }
1561
+
1562
+ func emitExecutionStartedEvent (ctx context.Context , cma custmsg.MessageEmitter , triggerID string ) error {
1563
+ metadata := buildWorkflowMetadata (cma .Labels ())
1564
+
1565
+ event := & pb.WorkflowExecutionStarted {
1566
+ M : metadata ,
1567
+ Timestamp : time .Now ().String (),
1568
+ TriggerID : triggerID ,
1569
+ }
1570
+
1571
+ return emitProtoMessage (ctx , event )
1572
+ }
1573
+
1574
+ func emitExecutionFinishedEvent (ctx context.Context , cma custmsg.MessageEmitter , status string ) error {
1575
+ metadata := buildWorkflowMetadata (cma .Labels ())
1576
+
1577
+ event := & pb.WorkflowExecutionFinished {
1578
+ M : metadata ,
1579
+ Timestamp : time .Now ().String (),
1580
+ Status : status ,
1581
+ }
1582
+
1583
+ return emitProtoMessage (ctx , event )
1584
+ }
1585
+
1586
+ func emitCapabilityStartedEvent (ctx context.Context , cma custmsg.MessageEmitter , capabilityID , stepRef string ) error {
1587
+ metadata := buildWorkflowMetadata (cma .Labels ())
1588
+
1589
+ event := & pb.CapabilityExecutionStarted {
1590
+ M : metadata ,
1591
+ Timestamp : time .Now ().String (),
1592
+ CapabilityID : capabilityID ,
1593
+ StepRef : stepRef ,
1594
+ }
1595
+
1596
+ return emitProtoMessage (ctx , event )
1597
+ }
1598
+
1599
+ func emitCapabilityFinishedEvent (ctx context.Context , cma custmsg.MessageEmitter , capabilityID , stepRef , status string ) error {
1600
+ metadata := buildWorkflowMetadata (cma .Labels ())
1601
+
1602
+ event := & pb.CapabilityExecutionFinished {
1603
+ M : metadata ,
1604
+ Timestamp : time .Now ().String (),
1605
+ CapabilityID : capabilityID ,
1606
+ StepRef : stepRef ,
1607
+ Status : status ,
1608
+ }
1609
+
1610
+ return emitProtoMessage (ctx , event )
1611
+ }
0 commit comments