salesforce implementation - phase 1#3939
salesforce implementation - phase 1#3939ness-david-dedu wants to merge 19 commits intoredpanda-data:mainfrom
Conversation
|
|
||
| func (*salesforceProcessor) Close(context.Context) error { return nil } | ||
|
|
||
| func init() { |
There was a problem hiding this comment.
minor: It's a common convention to put init functions at the top of the file under constants/variables as the first function so it's lifecycle is clear to readers. You'll see the same convention used throughout other components.
internal/impl/salesforce/salesforcehttp/http_metrics/http_metrics.go
Outdated
Show resolved
Hide resolved
|
|
||
| query := apiUrl.Query() | ||
| query.Set("grant_type", "client_credentials") | ||
| query.Set("client_id", s.clientId) |
There was a problem hiding this comment.
| query.Set("client_id", s.clientId) | |
| query.Set("client_id", s.clientID) |
Minor: Follow the Go convention of uppercase acronyms.
There was a problem hiding this comment.
Also, aren't these supposed to be sent in the request-body instead of the query string?
There was a problem hiding this comment.
done, moved to request body
| // This is the general function that calls Salesforce API on a specific URL using the URL object. | ||
| // It applies standard header parameters to all calls, Authorization, User-Agent and Accept. | ||
| // It uses the helper functions to check against possible response codes and handling the retry-after mechanism | ||
| func (s *Client) callSalesforceApi(ctx context.Context, u *url.URL) ([]byte, error) { |
There was a problem hiding this comment.
| func (s *Client) callSalesforceApi(ctx context.Context, u *url.URL) ([]byte, error) { | |
| func (s *Client) callSalesforceAPI(ctx context.Context, u *url.URL) ([]byte, error) { |
Co-authored-by: Joseph Woodward <joseph.woodward@xeuse.com>
Co-authored-by: Joseph Woodward <joseph.woodward@xeuse.com>
…ics.go Co-authored-by: Joseph Woodward <joseph.woodward@xeuse.com>
| retryBody, retryErr := s.doSalesforceRequest(ctx, u) | ||
|
|
||
| if retryErr != nil { | ||
| return nil, fmt.Errorf("request failed: %v", retryErr) |
There was a problem hiding this comment.
Given this module will change with the connector, it's probably better to wrap the error with %w instead of %v. Same for other instances I see exist in these files.
| inflightVal int64 // track ourselves; gauge uses Set() | ||
| total *service.MetricCounter | ||
| errors *service.MetricCounter | ||
| status2xx *service.MetricCounter |
There was a problem hiding this comment.
Do we use a metric per status code in other components? My understanding is it's better to have a status code as a label? It'd be worth looking at some other components capturing HTTP metrics to see if there's a pattern. This is definitely something we should look to standardise though.
There was a problem hiding this comment.
changed to using a label
Co-authored-by: Joseph Woodward <joseph.woodward@xeuse.com>
Co-authored-by: Joseph Woodward <joseph.woodward@xeuse.com>
Co-authored-by: Joseph Woodward <joseph.woodward@xeuse.com>
Co-authored-by: Joseph Woodward <joseph.woodward@xeuse.com>
Co-authored-by: Joseph Woodward <joseph.woodward@xeuse.com>
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
|
|
||
| // types.go defines core data structures, response models, and enums for the Jira processor. |
There was a problem hiding this comment.
| // types.go defines core data structures, response models, and enums for the Jira processor. | |
| // types.go defines core data structures, response models, and enums for the Salesforce processor. |
| if err != nil { | ||
| return nil, fmt.Errorf("invalid URL: %w", err) | ||
| } | ||
|
|
There was a problem hiding this comment.
We should remove the q=query param from the concatenated string and encode/escape it properly:
q := apiUrl.Query()
q.Set("q", query)
apiUrl.RawQuery = q.Encode() | // 1. Basic request and auth check | ||
| // | ||
| // ctx := context.Background() | ||
| // req, _ := http.NewRequestWithContext(ctx, http.MethodGet, "https:your-domain.atlassian.net/rest/api/3/myself", nil) |
There was a problem hiding this comment.
Looks like this is from the Jira example? We should update the documentation to a working salesforce example.
| // metrics such as in-flight requests, response status codes, errors, and request duration. | ||
| func NewInstrumentedClient(m *service.Metrics, namespace string, client *http.Client) *http.Client { | ||
| if client == nil { | ||
| client = &http.Client{} |
There was a problem hiding this comment.
Is there any reason to use http.Client here instead of http.DefaultClient as you have done in DoRequestWithRetries?
| } | ||
|
|
||
| // NewClient is the constructor for a Client object | ||
| func NewClient(log *service.Logger, orgUrl, clientId, clientSecret, apiVersion string, maxRetries int, metrics *service.Metrics, httpClient *http.Client) (*Client, error) { |
There was a problem hiding this comment.
| func NewClient(log *service.Logger, orgUrl, clientId, clientSecret, apiVersion string, maxRetries int, metrics *service.Metrics, httpClient *http.Client) (*Client, error) { | |
| func NewClient(log *service.Logger, orgURL, clientID, clientSecret, apiVersion string, maxRetries int, metrics *service.Metrics, httpClient *http.Client) (*Client, error) { |
There was a problem hiding this comment.
Also, arguments are usually supplied in terms of importance and relevance, so something like logger and metrics would be at the end, for instance:
httpClient *http.Client, orgUrl, clientId, clientSecret, apiVersion string, maxRetries int, metrics *service.Metrics, log *service.Logger
There was a problem hiding this comment.
updated the arguments order:
- orgURL, clientID, clientSecret — connection identity
- apiVersion, maxRetries — behavioral config
- httpClient, log, metrics — infrastructure/dependencies
|
|
||
| req.Header.Set("Accept", "application/json") | ||
| req.Header.Set("User-Agent", "Redpanda-Connect") | ||
| req.Header.Set("Authorization", "Bearer "+s.bearerToken) |
There was a problem hiding this comment.
Do we need to guard token access with a mutex to prevent data races with access to the token?
| if err != nil { | ||
| return nil, err | ||
| } | ||
| s.log.Debugf("Fetching from Salesforce.. Input: %s", string(inputMsg)) |
There was a problem hiding this comment.
I presume this will go once the processor implementation is complete?
| return nil, err | ||
| } | ||
|
|
||
| maxRetries, err := conf.FieldInt("max_retries") |
There was a problem hiding this comment.
We should probably validate this for negative retries.
| func (s *Client) updateAndSetBearerToken(ctx context.Context) error { | ||
| apiUrl, err := url.Parse(s.orgURL + salesforceAPIBasePath + "/oauth2/token") | ||
| if err != nil { | ||
| return fmt.Errorf("invalid URL: %w", err) |
There was a problem hiding this comment.
Would be good to add a bit more context to these kinds of errors, such as "invalid token endpoint url" to make it clearer to readers what part is invalid.
| })) | ||
| defer ts.Close() | ||
|
|
||
| // log := service.NewLogger("test") |
There was a problem hiding this comment.
Are these comments needed?
| clientID string | ||
| clientSecret string | ||
| apiVersion string | ||
| bearerToken string |
There was a problem hiding this comment.
I'd maybe suggest having an atomic string here instead of a mutex since it seems to only be getted and setted rather than used in a multiple line interaction.
| attempt := 0 | ||
|
|
||
| for { | ||
| resp, err := client.Do(req.WithContext(ctx)) |
There was a problem hiding this comment.
After the first iteration this request will have already flushed its body, and so it'll be empty if this is a POST request. Instead you'll need to reconstruct the request for each iteration. A quick solution is to change the req param into a reqBuilder func() *http.Request.
| } | ||
| } | ||
|
|
||
| defer resp.Body.Close() |
There was a problem hiding this comment.
Since we're inside a loop I would move this below the read and make it immediate
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
|
|
||
| package http_metrics |
There was a problem hiding this comment.
We don't generally use underscores in package names, I would simply name this metrics.
No description provided.