Skip to content

Conversation

@denis-chernov-smartcontract
Copy link

@denis-chernov-smartcontract denis-chernov-smartcontract commented Dec 16, 2025

Closes DS-1421, DS-1423

Description

Implements the following functionality:

  • One metrics endpoint: http_requests_total
  • Metrics middleware
  • Redcon service that implements Redis mock service
  • API server
  • Main file

@changeset-bot
Copy link

changeset-bot bot commented Dec 16, 2025

⚠️ No Changeset found

Latest commit: 2565d63

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

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

Comment on lines +21 to +22
maxWaitTime := 60 * time.Second
checkInterval := 500 * time.Millisecond
Copy link

Choose a reason for hiding this comment

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

nit: These sounds like good candidates for config values.

This is true for most numbers that appear in the PR - web server configs and so on. This doesn't mean we NEED them in a conf or that moving them to a conf needs to happen in this PR.

Comment on lines +32 to +36
// Check if we've exceeded the maximum wait time
if time.Since(startTime) > maxWaitTime {
logger.Error("EA server did not become ready within timeout", "timeout", maxWaitTime)
log.Fatal("EA server startup timeout")
}
Copy link

Choose a reason for hiding this comment

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

This works as is and needs no change.

That said, the more idiomatic way to do the same thing would be to define a timer outside the loop:

timer := time.After(maxWaitTime)

and then replace the block above with this:

		select {
		case <-timer:
			logger.Error("EA server did not become ready within timeout", "timeout", maxWaitTime)
			log.Fatal("EA server startup timeout")
		default:
		}

The reason we prefer this is that is gives us a very clean way to add multiple blocking conditions in there (channels, state, etc.).

As I said above, the current code needs no change.

Comment on lines +40 to +44
if err == nil && resp.StatusCode == http.StatusOK {
resp.Body.Close()
logger.Info("EA server is ready", "elapsed", time.Since(startTime))
return
}
Copy link

Choose a reason for hiding this comment

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

We wait for the EA to be able to respond successfully to a /health call.
Do we need to inspect the body of the response? Is there a case where the EA might respond successfully but still be unhealthy?

})

// Create error channel for goroutine failures
errChan := make(chan error, 1)
Copy link

Choose a reason for hiding this comment

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

I don't see where we read from this channel. I see that we write to it from the goroutine but I don't see a read.

Comment on lines +96 to +98
if err := redconServer.Start(); err != nil {
log.Fatal(err)
}
Copy link

Choose a reason for hiding this comment

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

I might need some help understanding how this ties to the web server, too. You mentioned this already. :)

httpClient *http.Client
subscriptionTracker sync.Map
metrics *appMetrics.Metrics
ctx context.Context // Add this
Copy link

Choose a reason for hiding this comment

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

the comment is probably outdated now.

defer errorResponsePool.Put(errorResp)

errorResp.Error.Name = "AdapterError"
errorResp.Error.Message = "Unable to subsribe to an asset pair with the the requested data"
Copy link

Choose a reason for hiding this comment

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

Suggested change
errorResp.Error.Message = "Unable to subsribe to an asset pair with the the requested data"
errorResp.Error.Message = "Unable to subscribe to an asset pair with the the requested data"

Comment on lines +289 to +300
if _, alreadySubscribing := s.subscriptionTracker.LoadOrStore(subscriptionKey, true); !alreadySubscribing {
s.logger.Debug("Initiating new subscription", "requestParams", canonicalParams, "subscriptionKey", subscriptionKey)
go func(key string, params types.RequestParams) {
s.subscribeToAsset(params)
// Remove from tracker after subscription attempt completes
// Allow retries after 10 seconds if data still not available
time.Sleep(10 * time.Second)
s.subscriptionTracker.Delete(key)
}(subscriptionKey, canonicalParams)
} else if s.config.LogLevel == "debug" {
s.logger.Debug("Subscription already in progress, skipping", "key", subscriptionKey)
}
Copy link

Choose a reason for hiding this comment

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

I will need some guidance here. :)

Comment on lines +321 to +323
for key, value := range params {
dataMap[key] = value
}
Copy link

Choose a reason for hiding this comment

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

Is there a reason to copy the data from params instead of using it directly?

Comment on lines +11 to +15
cache "streams-adapter/cache"
config "streams-adapter/config"
helpers "streams-adapter/helpers"
redcon "streams-adapter/redcon"
server "streams-adapter/server"
Copy link

Choose a reason for hiding this comment

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

nit: These aliases are redundant.

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.

2 participants