Skip to content

[CLD-354]: feat(operation): support execution of dynamic operation #174

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 13, 2025

Conversation

graham-chainlink
Copy link
Collaborator

@graham-chainlink graham-chainlink commented Jun 11, 2025

To enhance the flexibility of Operations API, we want to support dynamic execution of Operation.

Based on the operation definition, we can decide on run time what operations to execute and what input and deps to pass in to that operation. This can be quite powerful to allow users to dynamically construct a series of operation under a sequence.

Refer to this example code snippet:

func ExampleOperationRegistry() {
	type Deps1 struct{}
	type Deps2 struct{}

	// Create operations with different input/output types
	stringOp := NewOperation(
		"string-op",
		semver.MustParse("1.0.0"),
		"Echo string operation",
		func(e Bundle, deps Deps1, input string) (string, error) {
			return input, nil
		},
	)

	intOp := NewOperation(
		"int-op",
		semver.MustParse("1.0.0"),
		"Echo integer operation",
		func(e Bundle, deps Deps2, input int) (int, error) {
			return input, nil
		},
	)
	// Create registry with untyped operations by providing optional initial operation
	registry := NewOperationRegistry(stringOp.AsUntyped())

	// An alternative way to register additional operations without calling AsUntyped()
	RegisterOperation(registry, intOp)

	// Create execution environment
	b := NewBundle(context.Background, logger.Nop(), NewMemoryReporter(), WithOperationRegistry(registry))

	inputs := []any{"input1", 42}
	deps := []any{Deps1{}, Deps2{}}
	defs := []Definition{
		stringOp.Def(),
		intOp.Def(),
	}

	// dynamically retrieve and execute operations on different inputs
	for i, def := range defs {
		retrievedOp, err := registry.Retrieve(def)
		if err != nil {
			fmt.Println("error retrieving operation:", err)
			continue
		}

		report, err := ExecuteOperation(b, retrievedOp, deps[i], inputs[i])
		if err != nil {
			fmt.Println("error executing operation:", err)
			continue
		}

		fmt.Println("operation output:", report.Output)
	}

	// Output:
	// operation output: input1
	// operation output: 42
}

JIRA: https://smartcontract-it.atlassian.net/browse/CLD-354

Copy link

changeset-bot bot commented Jun 11, 2025

🦋 Changeset detected

Latest commit: f23f6b6

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
chainlink-deployments-framework Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@graham-chainlink graham-chainlink force-pushed the ggoh/prototype/dynamic-execution branch 3 times, most recently from 1f3e1eb to 8371a5a Compare June 11, 2025 15:24
@graham-chainlink graham-chainlink changed the title protyping on dynamic operation execution [CLD-354]: feat(operation): support execution of dynamic operation Jun 11, 2025
@graham-chainlink graham-chainlink marked this pull request as ready for review June 11, 2025 15:39
@graham-chainlink graham-chainlink requested a review from a team as a code owner June 11, 2025 15:39
@graham-chainlink graham-chainlink force-pushed the ggoh/prototype/dynamic-execution branch from 8371a5a to 1e4b1c1 Compare June 12, 2025 01:59
To enhance the flexibility of Operations API, we want to support dynamic execution of Operation.
Imagine this snippet of code:

```
    inputs := []any{"input1", 42}
	deps := []any{Deps1{}, Deps2{}}
	defs := []Definition{
		{ID: "string-op", Version: semver.MustParse("1.0.0")},
		{ID: "int-op", Version: semver.MustParse("1.0.0")},
	}

	// dynamically retrieve and execute operations on different inputs
	for i, def := range defs {
	    // registry contains a list of operations
		retrievedOp, _ := registry.Retrieve(def)
		// dependency and input are dynamic/different per Operation
		report, _ := ExecuteOperation(b, retrievedOp, deps[i], inputs[i])
	}
```

Based on the definition, we can decide on run time what operations to execute and what input and deps to pass in to that operation. This can be quite powerful to allow users to dynamically construct a series of operation under a sequence.

JIRA: https://smartcontract-it.atlassian.net/browse/CLD-354
@graham-chainlink graham-chainlink force-pushed the ggoh/prototype/dynamic-execution branch from 1e4b1c1 to ec99ee5 Compare June 12, 2025 02:11
RodrigoAD
RodrigoAD previously approved these changes Jun 12, 2025
Copy link
Member

@RodrigoAD RodrigoAD left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @graham-chainlink ! LGTM :)

},
)
// Create registry with untyped operations
registry := NewOperationRegistry(stringOp.AsUntyped(), intOp.AsUntyped())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is more of a question.

Could NewOperationRegistry call AsUntyped() to any provided inputs? Then the user doesn't have to remember doing that for every input 🤔

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could NewOperationRegistry call AsUntyped() to any provided inputs?

haha well for NewOperationRegistry to accept any input in the first place, we have to call AsUntyped to convert it into any type.

so we cant do

r := NewOperationRegistry(stringOp, intOp)
// then call untype inside 

because the parameter NewOperationRegistry has to be any type in order to accept any operations as each operation has different types for input, output if that make sense

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alright added a helper

         // Create registry with untyped operations by providing optional initial operation
	registry := NewOperationRegistry(stringOp.AsUntyped())

	// An alternative way to register additional operations without calling AsUntyped()
	RegisterOperation(registry, intOp)

giogam
giogam previously approved these changes Jun 13, 2025
ajaskolski
ajaskolski previously approved these changes Jun 13, 2025
@cl-sonarqube-production
Copy link

@DimitriosNaikopoulos DimitriosNaikopoulos self-requested a review June 13, 2025 08:01
@graham-chainlink graham-chainlink added this pull request to the merge queue Jun 13, 2025
Merged via the queue into main with commit 4a4f9b2 Jun 13, 2025
8 checks passed
@graham-chainlink graham-chainlink deleted the ggoh/prototype/dynamic-execution branch June 13, 2025 08:16
github-merge-queue bot pushed a commit that referenced this pull request Jun 13, 2025
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## chainlink-deployments-framework@0.13.0

### Minor Changes

-
[#174](#174)
[`4a4f9b2`](4a4f9b2)
Thanks [@graham-chainlink](https://github.com/graham-chainlink)! - feat:
support dynamic execution of operation

-
[#166](#166)
[`f5a2ca9`](f5a2ca9)
Thanks [@jkongie](https://github.com/jkongie)! - Adds a zkSync CTF
provider under the EVM Chain

---------

Co-authored-by: app-token-issuer-engops[bot] <144731339+app-token-issuer-engops[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants