Skip to content
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

implement HTTP target capability and connector handler #14491

Open
wants to merge 8 commits into
base: develop
Choose a base branch
from

Conversation

jinhoonbang
Copy link
Contributor

@jinhoonbang jinhoonbang commented Sep 19, 2024

  • implement HTTP target capability that makes outbound HTTP calls via the gateway. It supports SingleNode mode, which forwards HTTP calls via the first available gateway. This is done through a new SignAndSendToGateway() method in the gateway connector that selects an available gateway and signs the request before sending it to the gateway
  • implement connector handler that receives response from the gateway and sychronously returns gateway response to capability.Execute()
  • corresponding changes for the gateway (e.g. http client for outgoing message and gateway handler) will be done in a separate PR

JIRA: https://smartcontract-it.atlassian.net/browse/CM-469
Doc: https://docs.google.com/document/d/19PvTwosdwqNztwP6vcXSdt_s81xZXpjKU-5bpwhsd2M/edit#heading=h.4e7ng0tekbkc

@jinhoonbang jinhoonbang marked this pull request as ready for review September 19, 2024 20:53
@jinhoonbang jinhoonbang requested a review from a team as a code owner September 19, 2024 20:53
return capabilities.CapabilityResponse{}, err
}

// TODO: check target response format and fields
Copy link
Contributor

Choose a reason for hiding this comment

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

When/how will this TODO get resolved?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I propose this struct. Thoughts?

type CapabilityResponsePayload struct {
	Success      bool     
	ErrorMessage string
	StatusCode   uint8   
	Headers      map[string]string 
	Body         string
}

@@ -0,0 +1,168 @@
package target
Copy link
Contributor

Choose a reason for hiding this comment

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

I remember seeing a discussion about naming and file structure, but I find capabilities/webapi/target/capability.go file exporting package target and tested by target_test.go to be a bit confusing. I'd prefer the filename to be target.go, even though that's redundant. But maybe there's general guidance against duplicating folder and filename.

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will make this change.

@@ -15,6 +15,7 @@ import (
const (
FunctionsHandlerType HandlerType = "functions"
DummyHandlerType HandlerType = "dummy"
WebCapabilitiesType HandlerType = "web-capabilities"
Copy link
Contributor

Choose a reason for hiding this comment

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

how about webapi-capabilities for consistency?

if len(spec.StandardCapabilitiesSpec.Config) == 0 {
return nil, errors.New("config is empty")
}
// TODO: check if TOML is the only supported format here
Copy link
Contributor

Choose a reason for hiding this comment

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

How does this TODO get resolved?

@@ -0,0 +1,6 @@
package webcapabilities
Copy link
Contributor

Choose a reason for hiding this comment

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

I suggest webapicapabilities for package

require.NoError(t, err)
}

func TestCapability_Execute(t *testing.T) {
Copy link
Contributor

Choose a reason for hiding this comment

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

what about invalid workflow id, workflow execution id, and other error scenarios?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will add those scenarios

Comment on lines +98 to +99
c.registeredWorkflowsMu.Lock()
defer c.registeredWorkflowsMu.Unlock()
Copy link
Contributor

Choose a reason for hiding this comment

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

is it necessary to hold the lock for the duration of this method or can it be released after reading the map?

Copy link
Contributor Author

@jinhoonbang jinhoonbang Sep 20, 2024

Choose a reason for hiding this comment

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

yep can release it after reading the map although i imagine contention on this lock is very low

registry core.CapabilitiesRegistry
config Config
registeredWorkflows map[string]struct{}
registeredWorkflowsMu sync.Mutex
Copy link
Contributor

Choose a reason for hiding this comment

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

nit RWMutex

gatewayIDs := c.gc.GatewayIDs()
sort.Strings(gatewayIDs)

err := c.gc.SignAndSendToGateway(ctx, gatewayIDs[0], body)
Copy link
Contributor

Choose a reason for hiding this comment

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

is gatewayIDs guaranteed to have length?

Copy link
Contributor Author

@jinhoonbang jinhoonbang Sep 20, 2024

Choose a reason for hiding this comment

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

sounds like a fatal set up error if it doesn't. But I wasn't able to find such validation. I can handle it more gracefully here.

l.Errorw("no response channel found")
return
}
ch <- msg
Copy link
Contributor

Choose a reason for hiding this comment

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

allow bypass of message send if ctx cancels even if channel is buffered

func TestCapability_Execute(t *testing.T) {
th := setup(t)
ctx := testutils.Context(t)
th.connector.On("DonID").Return("donID")
Copy link
Contributor

Choose a reason for hiding this comment

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

use .EXPECT() for type safety

type ConnectorHandler struct {
gc connector.GatewayConnector
lggr logger.Logger
responseChs map[string]chan *api.Message
Copy link
Contributor

Choose a reason for hiding this comment

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

how big do we expect this map to get? creates a new entry for every request, we probably need a cleanup after each read

Copy link
Contributor Author

Choose a reason for hiding this comment

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

makes sense. will make that change

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.

3 participants