Add new job to save token insights to the database - #352

Merged
rickyrombo merged 1 commit into
mjp-dbc-pricesfrom
mjp-scheduled-insights
Sep 3, 2025
Merged

Add new job to save token insights to the database#352
rickyrombo merged 1 commit into
mjp-dbc-pricesfrom
mjp-scheduled-insights

Conversation

@rickyrombo

Copy link
Copy Markdown
Contributor
  • Adds new jobs package to hold "jobs"
  • Adds new artist_coin_stats table to hold token insights
  • Creates new job for saving token insights
  • Runs the artist coin stats job in Solana Indexer

Also:

  • Moves the Birdeye client to its own package
  • Moves scheduling of retries to own function in the solana indexer
  • Replaces With(zap.String("service", "SolanaIndexer") with Named("SolanaIndexer")
  • Makes previous migrations idempotent
  • Moves DbPool interface to database package to be shared

go s.ScheduleRetries(ctx, s.config.SolanaIndexerRetryInterval)

go jobs.NewCoinStatsJob(s.config, s.pool).
ScheduleEvery(ctx, 5*time.Minute)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Config for this interval? TBH not sure if there's a benefit. Deploying a new config is much like deploying a code change 🤷

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I 100000% agree with this

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

In late to say at the very least these should be named constants defined in a centralized config object instead of inline in a function. But that's a nitpick.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

why?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I did say nitpick, but I think a config object (a constant, not env variables) is easier for somebody who didn't write the code to come in and adjust the value if needed than having to dig through to find where it's passed. Just a stylistic preference.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I think if the initialization of jobs are all short one liners and listed together that's probably good enough. But if there initialized all over the place or are more complicated to init it may get harder to grok

@raymondjacobsonraymondjacobson left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nice looks great!

@@ -1,2 +1,2 @@
ALTER TABLE artist_coins
ADD COLUMN name TEXT NOT NULL DEFAULT ''; No newline at end of file
ADD COLUMN IF NOT EXISTS name TEXT NOT NULL DEFAULT ''; No newline at end of file

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

👍

Comment threadjobs/coin_stats.go
}

for offset := 0; offset < count; offset += tokenPageSize {
batch, err := j.getTokenBatch(ctx, tokenPageSize, offset)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think batch is kinda overkill, could just paginate 1 by 1 and fetch i think. but this works

go s.ScheduleRetries(ctx, s.config.SolanaIndexerRetryInterval)

go jobs.NewCoinStatsJob(s.config, s.pool).
ScheduleEvery(ctx, 5*time.Minute)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I 100000% agree with this

@rickyrombo
rickyrombo merged commit 5f1d684 into mjp-dbc-pricesSep 3, 2025
4 checks passed
@rickyrombo
rickyrombo deleted the mjp-scheduled-insights branch September 3, 2025 16:40
Sign up for freeto 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

@rickyrombo@schottra@raymondjacobson
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Add new job to save token insights to the database - #352

Merged
rickyrombo merged 1 commit into
mjp-dbc-pricesfrom
mjp-scheduled-insights
Sep 3, 2025
Merged

Add new job to save token insights to the database#352
rickyrombo merged 1 commit into
mjp-dbc-pricesfrom
mjp-scheduled-insights

Conversation

@rickyrombo

Copy link
Copy Markdown
Contributor
  • Adds new jobs package to hold "jobs"
  • Adds new artist_coin_stats table to hold token insights
  • Creates new job for saving token insights
  • Runs the artist coin stats job in Solana Indexer

Also:

  • Moves the Birdeye client to its own package
  • Moves scheduling of retries to own function in the solana indexer
  • Replaces With(zap.String("service", "SolanaIndexer") with Named("SolanaIndexer")
  • Makes previous migrations idempotent
  • Moves DbPool interface to database package to be shared

go s.ScheduleRetries(ctx, s.config.SolanaIndexerRetryInterval)

go jobs.NewCoinStatsJob(s.config, s.pool).
ScheduleEvery(ctx, 5*time.Minute)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Config for this interval? TBH not sure if there's a benefit. Deploying a new config is much like deploying a code change 🤷

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I 100000% agree with this

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

In late to say at the very least these should be named constants defined in a centralized config object instead of inline in a function. But that's a nitpick.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

why?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I did say nitpick, but I think a config object (a constant, not env variables) is easier for somebody who didn't write the code to come in and adjust the value if needed than having to dig through to find where it's passed. Just a stylistic preference.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I think if the initialization of jobs are all short one liners and listed together that's probably good enough. But if there initialized all over the place or are more complicated to init it may get harder to grok

@raymondjacobsonraymondjacobson left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nice looks great!

@@ -1,2 +1,2 @@
ALTER TABLE artist_coins
ADD COLUMN name TEXT NOT NULL DEFAULT ''; No newline at end of file
ADD COLUMN IF NOT EXISTS name TEXT NOT NULL DEFAULT ''; No newline at end of file

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

👍

Comment threadjobs/coin_stats.go
}

for offset := 0; offset < count; offset += tokenPageSize {
batch, err := j.getTokenBatch(ctx, tokenPageSize, offset)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think batch is kinda overkill, could just paginate 1 by 1 and fetch i think. but this works

go s.ScheduleRetries(ctx, s.config.SolanaIndexerRetryInterval)

go jobs.NewCoinStatsJob(s.config, s.pool).
ScheduleEvery(ctx, 5*time.Minute)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I 100000% agree with this

@rickyrombo
rickyrombo merged commit 5f1d684 into mjp-dbc-pricesSep 3, 2025
4 checks passed
@rickyrombo
rickyrombo deleted the mjp-scheduled-insights branch September 3, 2025 16:40
Sign up for freeto 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

@rickyrombo@schottra@raymondjacobson
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add new job to save token insights to the database - #352

Merged
rickyrombo merged 1 commit into
mjp-dbc-pricesfrom
mjp-scheduled-insights
Sep 3, 2025
Merged

Add new job to save token insights to the database#352
rickyrombo merged 1 commit into
mjp-dbc-pricesfrom
mjp-scheduled-insights

Conversation

@rickyrombo

Copy link
Copy Markdown
Contributor
  • Adds new jobs package to hold "jobs"
  • Adds new artist_coin_stats table to hold token insights
  • Creates new job for saving token insights
  • Runs the artist coin stats job in Solana Indexer

Also:

  • Moves the Birdeye client to its own package
  • Moves scheduling of retries to own function in the solana indexer
  • Replaces With(zap.String("service", "SolanaIndexer") with Named("SolanaIndexer")
  • Makes previous migrations idempotent
  • Moves DbPool interface to database package to be shared

go s.ScheduleRetries(ctx, s.config.SolanaIndexerRetryInterval)

go jobs.NewCoinStatsJob(s.config, s.pool).
ScheduleEvery(ctx, 5*time.Minute)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Config for this interval? TBH not sure if there's a benefit. Deploying a new config is much like deploying a code change 🤷

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I 100000% agree with this

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

In late to say at the very least these should be named constants defined in a centralized config object instead of inline in a function. But that's a nitpick.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

why?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I did say nitpick, but I think a config object (a constant, not env variables) is easier for somebody who didn't write the code to come in and adjust the value if needed than having to dig through to find where it's passed. Just a stylistic preference.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I think if the initialization of jobs are all short one liners and listed together that's probably good enough. But if there initialized all over the place or are more complicated to init it may get harder to grok

@raymondjacobsonraymondjacobson left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nice looks great!

@@ -1,2 +1,2 @@
ALTER TABLE artist_coins
ADD COLUMN name TEXT NOT NULL DEFAULT ''; No newline at end of file
ADD COLUMN IF NOT EXISTS name TEXT NOT NULL DEFAULT ''; No newline at end of file

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

👍

Comment threadjobs/coin_stats.go
}

for offset := 0; offset < count; offset += tokenPageSize {
batch, err := j.getTokenBatch(ctx, tokenPageSize, offset)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think batch is kinda overkill, could just paginate 1 by 1 and fetch i think. but this works

go s.ScheduleRetries(ctx, s.config.SolanaIndexerRetryInterval)

go jobs.NewCoinStatsJob(s.config, s.pool).
ScheduleEvery(ctx, 5*time.Minute)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I 100000% agree with this

@rickyrombo
rickyrombo merged commit 5f1d684 into mjp-dbc-pricesSep 3, 2025
4 checks passed
@rickyrombo
rickyrombo deleted the mjp-scheduled-insights branch September 3, 2025 16:40
Sign up for freeto 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

@rickyrombo@schottra@raymondjacobson
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add new job to save token insights to the database - #352

Merged
rickyrombo merged 1 commit into
mjp-dbc-pricesfrom
mjp-scheduled-insights
Sep 3, 2025
Merged

Add new job to save token insights to the database#352
rickyrombo merged 1 commit into
mjp-dbc-pricesfrom
mjp-scheduled-insights

Conversation

@rickyrombo

Copy link
Copy Markdown
Contributor
  • Adds new jobs package to hold "jobs"
  • Adds new artist_coin_stats table to hold token insights
  • Creates new job for saving token insights
  • Runs the artist coin stats job in Solana Indexer

Also:

  • Moves the Birdeye client to its own package
  • Moves scheduling of retries to own function in the solana indexer
  • Replaces With(zap.String("service", "SolanaIndexer") with Named("SolanaIndexer")
  • Makes previous migrations idempotent
  • Moves DbPool interface to database package to be shared

go s.ScheduleRetries(ctx, s.config.SolanaIndexerRetryInterval)

go jobs.NewCoinStatsJob(s.config, s.pool).
ScheduleEvery(ctx, 5*time.Minute)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Config for this interval? TBH not sure if there's a benefit. Deploying a new config is much like deploying a code change 🤷

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I 100000% agree with this

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

In late to say at the very least these should be named constants defined in a centralized config object instead of inline in a function. But that's a nitpick.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

why?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I did say nitpick, but I think a config object (a constant, not env variables) is easier for somebody who didn't write the code to come in and adjust the value if needed than having to dig through to find where it's passed. Just a stylistic preference.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I think if the initialization of jobs are all short one liners and listed together that's probably good enough. But if there initialized all over the place or are more complicated to init it may get harder to grok

@raymondjacobsonraymondjacobson left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nice looks great!

@@ -1,2 +1,2 @@
ALTER TABLE artist_coins
ADD COLUMN name TEXT NOT NULL DEFAULT ''; No newline at end of file
ADD COLUMN IF NOT EXISTS name TEXT NOT NULL DEFAULT ''; No newline at end of file

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

👍

Comment threadjobs/coin_stats.go
}

for offset := 0; offset < count; offset += tokenPageSize {
batch, err := j.getTokenBatch(ctx, tokenPageSize, offset)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think batch is kinda overkill, could just paginate 1 by 1 and fetch i think. but this works

go s.ScheduleRetries(ctx, s.config.SolanaIndexerRetryInterval)

go jobs.NewCoinStatsJob(s.config, s.pool).
ScheduleEvery(ctx, 5*time.Minute)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I 100000% agree with this

@rickyrombo
rickyrombo merged commit 5f1d684 into mjp-dbc-pricesSep 3, 2025
4 checks passed
@rickyrombo
rickyrombo deleted the mjp-scheduled-insights branch September 3, 2025 16:40
Sign up for freeto 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

@rickyrombo@schottra@raymondjacobson
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Add new job to save token insights to the database - #352

Merged
rickyrombo merged 1 commit into
mjp-dbc-pricesfrom
mjp-scheduled-insights
Sep 3, 2025
Merged

Add new job to save token insights to the database#352
rickyrombo merged 1 commit into
mjp-dbc-pricesfrom
mjp-scheduled-insights

Conversation

@rickyrombo

Copy link
Copy Markdown
Contributor
  • Adds new jobs package to hold "jobs"
  • Adds new artist_coin_stats table to hold token insights
  • Creates new job for saving token insights
  • Runs the artist coin stats job in Solana Indexer

Also:

  • Moves the Birdeye client to its own package
  • Moves scheduling of retries to own function in the solana indexer
  • Replaces With(zap.String("service", "SolanaIndexer") with Named("SolanaIndexer")
  • Makes previous migrations idempotent
  • Moves DbPool interface to database package to be shared

go s.ScheduleRetries(ctx, s.config.SolanaIndexerRetryInterval)

go jobs.NewCoinStatsJob(s.config, s.pool).
ScheduleEvery(ctx, 5*time.Minute)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Config for this interval? TBH not sure if there's a benefit. Deploying a new config is much like deploying a code change 🤷

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I 100000% agree with this

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

In late to say at the very least these should be named constants defined in a centralized config object instead of inline in a function. But that's a nitpick.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

why?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I did say nitpick, but I think a config object (a constant, not env variables) is easier for somebody who didn't write the code to come in and adjust the value if needed than having to dig through to find where it's passed. Just a stylistic preference.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I think if the initialization of jobs are all short one liners and listed together that's probably good enough. But if there initialized all over the place or are more complicated to init it may get harder to grok

@raymondjacobsonraymondjacobson left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nice looks great!

@@ -1,2 +1,2 @@
ALTER TABLE artist_coins
ADD COLUMN name TEXT NOT NULL DEFAULT ''; No newline at end of file
ADD COLUMN IF NOT EXISTS name TEXT NOT NULL DEFAULT ''; No newline at end of file

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

👍

Comment threadjobs/coin_stats.go
}

for offset := 0; offset < count; offset += tokenPageSize {
batch, err := j.getTokenBatch(ctx, tokenPageSize, offset)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think batch is kinda overkill, could just paginate 1 by 1 and fetch i think. but this works

go s.ScheduleRetries(ctx, s.config.SolanaIndexerRetryInterval)

go jobs.NewCoinStatsJob(s.config, s.pool).
ScheduleEvery(ctx, 5*time.Minute)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I 100000% agree with this

@rickyrombo
rickyrombo merged commit 5f1d684 into mjp-dbc-pricesSep 3, 2025
4 checks passed
@rickyrombo
rickyrombo deleted the mjp-scheduled-insights branch September 3, 2025 16:40
Sign up for freeto 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

@rickyrombo@schottra@raymondjacobson
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add new job to save token insights to the database - #352

Merged
rickyrombo merged 1 commit into
mjp-dbc-pricesfrom
mjp-scheduled-insights
Sep 3, 2025
Merged

Add new job to save token insights to the database#352
rickyrombo merged 1 commit into
mjp-dbc-pricesfrom
mjp-scheduled-insights

Conversation

@rickyrombo

Copy link
Copy Markdown
Contributor
  • Adds new jobs package to hold "jobs"
  • Adds new artist_coin_stats table to hold token insights
  • Creates new job for saving token insights
  • Runs the artist coin stats job in Solana Indexer

Also:

  • Moves the Birdeye client to its own package
  • Moves scheduling of retries to own function in the solana indexer
  • Replaces With(zap.String("service", "SolanaIndexer") with Named("SolanaIndexer")
  • Makes previous migrations idempotent
  • Moves DbPool interface to database package to be shared

go s.ScheduleRetries(ctx, s.config.SolanaIndexerRetryInterval)

go jobs.NewCoinStatsJob(s.config, s.pool).
ScheduleEvery(ctx, 5*time.Minute)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Config for this interval? TBH not sure if there's a benefit. Deploying a new config is much like deploying a code change 🤷

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I 100000% agree with this

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

In late to say at the very least these should be named constants defined in a centralized config object instead of inline in a function. But that's a nitpick.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

why?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I did say nitpick, but I think a config object (a constant, not env variables) is easier for somebody who didn't write the code to come in and adjust the value if needed than having to dig through to find where it's passed. Just a stylistic preference.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I think if the initialization of jobs are all short one liners and listed together that's probably good enough. But if there initialized all over the place or are more complicated to init it may get harder to grok

@raymondjacobsonraymondjacobson left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nice looks great!

@@ -1,2 +1,2 @@
ALTER TABLE artist_coins
ADD COLUMN name TEXT NOT NULL DEFAULT ''; No newline at end of file
ADD COLUMN IF NOT EXISTS name TEXT NOT NULL DEFAULT ''; No newline at end of file

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

👍

Comment threadjobs/coin_stats.go
}

for offset := 0; offset < count; offset += tokenPageSize {
batch, err := j.getTokenBatch(ctx, tokenPageSize, offset)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think batch is kinda overkill, could just paginate 1 by 1 and fetch i think. but this works

go s.ScheduleRetries(ctx, s.config.SolanaIndexerRetryInterval)

go jobs.NewCoinStatsJob(s.config, s.pool).
ScheduleEvery(ctx, 5*time.Minute)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I 100000% agree with this

@rickyrombo
rickyrombo merged commit 5f1d684 into mjp-dbc-pricesSep 3, 2025
4 checks passed
@rickyrombo
rickyrombo deleted the mjp-scheduled-insights branch September 3, 2025 16:40
Sign up for freeto 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

@rickyrombo@schottra@raymondjacobson
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add new job to save token insights to the database - #352

Merged
rickyrombo merged 1 commit into
mjp-dbc-pricesfrom
mjp-scheduled-insights
Sep 3, 2025
Merged

Add new job to save token insights to the database#352
rickyrombo merged 1 commit into
mjp-dbc-pricesfrom
mjp-scheduled-insights

Conversation

@rickyrombo

Copy link
Copy Markdown
Contributor
  • Adds new jobs package to hold "jobs"
  • Adds new artist_coin_stats table to hold token insights
  • Creates new job for saving token insights
  • Runs the artist coin stats job in Solana Indexer

Also:

  • Moves the Birdeye client to its own package
  • Moves scheduling of retries to own function in the solana indexer
  • Replaces With(zap.String("service", "SolanaIndexer") with Named("SolanaIndexer")
  • Makes previous migrations idempotent
  • Moves DbPool interface to database package to be shared

go s.ScheduleRetries(ctx, s.config.SolanaIndexerRetryInterval)

go jobs.NewCoinStatsJob(s.config, s.pool).
ScheduleEvery(ctx, 5*time.Minute)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Config for this interval? TBH not sure if there's a benefit. Deploying a new config is much like deploying a code change 🤷

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I 100000% agree with this

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

In late to say at the very least these should be named constants defined in a centralized config object instead of inline in a function. But that's a nitpick.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

why?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I did say nitpick, but I think a config object (a constant, not env variables) is easier for somebody who didn't write the code to come in and adjust the value if needed than having to dig through to find where it's passed. Just a stylistic preference.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I think if the initialization of jobs are all short one liners and listed together that's probably good enough. But if there initialized all over the place or are more complicated to init it may get harder to grok

@raymondjacobsonraymondjacobson left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nice looks great!

@@ -1,2 +1,2 @@
ALTER TABLE artist_coins
ADD COLUMN name TEXT NOT NULL DEFAULT ''; No newline at end of file
ADD COLUMN IF NOT EXISTS name TEXT NOT NULL DEFAULT ''; No newline at end of file

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

👍

Comment threadjobs/coin_stats.go
}

for offset := 0; offset < count; offset += tokenPageSize {
batch, err := j.getTokenBatch(ctx, tokenPageSize, offset)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think batch is kinda overkill, could just paginate 1 by 1 and fetch i think. but this works

go s.ScheduleRetries(ctx, s.config.SolanaIndexerRetryInterval)

go jobs.NewCoinStatsJob(s.config, s.pool).
ScheduleEvery(ctx, 5*time.Minute)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I 100000% agree with this

@rickyrombo
rickyrombo merged commit 5f1d684 into mjp-dbc-pricesSep 3, 2025
4 checks passed
@rickyrombo
rickyrombo deleted the mjp-scheduled-insights branch September 3, 2025 16:40
Sign up for freeto 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

@rickyrombo@schottra@raymondjacobson
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Add new job to save token insights to the database - #352

Merged
rickyrombo merged 1 commit into
mjp-dbc-pricesfrom
mjp-scheduled-insights
Sep 3, 2025
Merged

Add new job to save token insights to the database#352
rickyrombo merged 1 commit into
mjp-dbc-pricesfrom
mjp-scheduled-insights

Conversation

@rickyrombo

Copy link
Copy Markdown
Contributor
  • Adds new jobs package to hold "jobs"
  • Adds new artist_coin_stats table to hold token insights
  • Creates new job for saving token insights
  • Runs the artist coin stats job in Solana Indexer

Also:

  • Moves the Birdeye client to its own package
  • Moves scheduling of retries to own function in the solana indexer
  • Replaces With(zap.String("service", "SolanaIndexer") with Named("SolanaIndexer")
  • Makes previous migrations idempotent
  • Moves DbPool interface to database package to be shared

go s.ScheduleRetries(ctx, s.config.SolanaIndexerRetryInterval)

go jobs.NewCoinStatsJob(s.config, s.pool).
ScheduleEvery(ctx, 5*time.Minute)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Config for this interval? TBH not sure if there's a benefit. Deploying a new config is much like deploying a code change 🤷

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I 100000% agree with this

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

In late to say at the very least these should be named constants defined in a centralized config object instead of inline in a function. But that's a nitpick.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

why?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I did say nitpick, but I think a config object (a constant, not env variables) is easier for somebody who didn't write the code to come in and adjust the value if needed than having to dig through to find where it's passed. Just a stylistic preference.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I think if the initialization of jobs are all short one liners and listed together that's probably good enough. But if there initialized all over the place or are more complicated to init it may get harder to grok

@raymondjacobsonraymondjacobson left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nice looks great!

@@ -1,2 +1,2 @@
ALTER TABLE artist_coins
ADD COLUMN name TEXT NOT NULL DEFAULT ''; No newline at end of file
ADD COLUMN IF NOT EXISTS name TEXT NOT NULL DEFAULT ''; No newline at end of file

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

👍

Comment threadjobs/coin_stats.go
}

for offset := 0; offset < count; offset += tokenPageSize {
batch, err := j.getTokenBatch(ctx, tokenPageSize, offset)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think batch is kinda overkill, could just paginate 1 by 1 and fetch i think. but this works

go s.ScheduleRetries(ctx, s.config.SolanaIndexerRetryInterval)

go jobs.NewCoinStatsJob(s.config, s.pool).
ScheduleEvery(ctx, 5*time.Minute)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I 100000% agree with this

@rickyrombo
rickyrombo merged commit 5f1d684 into mjp-dbc-pricesSep 3, 2025
4 checks passed
@rickyrombo
rickyrombo deleted the mjp-scheduled-insights branch September 3, 2025 16:40
Sign up for freeto 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

@rickyrombo@schottra@raymondjacobson