Skip to content

Comments

feat: feed sync#419

Merged
alanrsoares merged 36 commits intomainfrom
feed-sync
Nov 5, 2025
Merged

feat: feed sync#419
alanrsoares merged 36 commits intomainfrom
feed-sync

Conversation

@mazzy89
Copy link

@mazzy89 mazzy89 commented Oct 27, 2025

This PR adds a new app to publish new posts to a Telegram channel.

It uses PostgreSQL logical replication to read new posts.

Closes #403

@netlify
Copy link

netlify bot commented Oct 27, 2025

Deploy Preview for dither-staging ready!

Name Link
🔨 Latest commit 3715c4e
🔍 Latest deploy log https://app.netlify.com/projects/dither-staging/deploys/690b3f6c0648ed00080da8bd
😎 Deploy Preview https://deploy-preview-419--dither-staging.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@jeronimoalbi jeronimoalbi self-requested a review October 27, 2025 14:06
@jeronimoalbi
Copy link
Member

jeronimoalbi commented Oct 28, 2025

@mazzy89 I have been trying to make subscriptions work locally but no matter what I do I end up with errors when FeedReplicationService starts. Did you manage to try the communication?

I'm not sure if it's a local issue.

The issue is on service subscribe. I can see that previous to that there is communication from the client, in the logs you can see initial replication slot creation query, so communication works. The issue is related to the protocol being used at some point, it seems, but so far I can't find the exact point.

Tried with PostgreSQL 14, 17 and 18.

Traceback:

> feed-sync@1.0.0 start /Users/jeronimoalbi/Projects/dither.chat/packages/feed-sync
> vite-node ./src/index.ts

node:events:498
      throw er; // Unhandled 'error' event
      ^

error: invalid frontend message type 0
    at Parser.parseErrorMessage (/Users/jeronimoalbi/Projects/dither.chat/node_modules/.pnpm/pg-protocol@1.10.3/node_modules/pg-protocol/src/parser.ts:369:69)
    at Parser.handlePacket (/Users/jeronimoalbi/Projects/dither.chat/node_modules/.pnpm/pg-protocol@1.10.3/node_modules/pg-protocol/src/parser.ts:187:21)
    at Parser.parse (/Users/jeronimoalbi/Projects/dither.chat/node_modules/.pnpm/pg-protocol@1.10.3/node_modules/pg-protocol/src/parser.ts:102:30)
    at Socket.<anonymous> (/Users/jeronimoalbi/Projects/dither.chat/node_modules/.pnpm/pg-protocol@1.10.3/node_modules/pg-protocol/src/index.ts:7:48)
    at Socket.emit (node:events:532:35)
    at addChunk (node:internal/streams/readable:559:12)
    at readableAddChunkPushByteMode (node:internal/streams/readable:510:3)
    at Socket.Readable.push (node:internal/streams/readable:390:5)
    at TCP.onStreamRead (node:internal/stream_base_commons:191:23)
Emitted 'error' event on Client instance at:
    at Client._handleErrorEvent (/Users/jeronimoalbi/Projects/dither.chat/node_modules/.pnpm/pg@8.16.3/node_modules/pg/lib/client.js:350:10)
    at Client._handleErrorMessage (/Users/jeronimoalbi/Projects/dither.chat/node_modules/.pnpm/pg@8.16.3/node_modules/pg/lib/client.js:361:12)
    at Connection.emit (node:events:532:35)
    at /Users/jeronimoalbi/Projects/dither.chat/node_modules/.pnpm/pg@8.16.3/node_modules/pg/lib/connection.js:116:12
    at Parser.parse (/Users/jeronimoalbi/Projects/dither.chat/node_modules/.pnpm/pg-protocol@1.10.3/node_modules/pg-protocol/src/parser.ts:103:9)
    at Socket.<anonymous> (/Users/jeronimoalbi/Projects/dither.chat/node_modules/.pnpm/pg-protocol@1.10.3/node_modules/pg-protocol/src/index.ts:7:48)
    [... lines matching original stack trace ...]
    at Socket.Readable.push (node:internal/streams/readable:390:5) {
  length: 91,
  severity: 'FATAL',
  code: '08P01',
  detail: undefined,
  hint: undefined,
  position: undefined,
  internalPosition: undefined,
  internalQuery: undefined,
  where: undefined,
  schema: undefined,
  table: undefined,
  column: undefined,
  dataType: undefined,
  constraint: undefined,
  file: 'postgres.c',
  line: '467',
  routine: 'SocketBackend'
}

PostgreSQL log:

FATAL:  invalid frontend message type 0

@mazzy89
Copy link
Author

mazzy89 commented Oct 28, 2025

If you have tried with the local stack nothing will work and it is expected. you would need to prepare and configure the whole db config for logical replication enabling at the level of the db the WAL set to logical and increase the number of the slots. At the current time tests have been conducted against provider db.

@jeronimoalbi
Copy link
Member

jeronimoalbi commented Oct 28, 2025

If you have tried with the local stack nothing will work and it is expected. you would need to prepare and configure the whole db config for logical replication enabling at the level of the db the WAL set to logical and increase the number of the slots. At the current time tests have been conducted against provider db.

I have done it:

wal_level = logical
max_wal_senders = 10
max_replication_slots = 10

Also:

SELECT pg_create_logical_replication_slot('slot1', 'pgoutput');
CREATE PUBLICATION general FOR ALL TABLES;

Being slot1 the slot name and general the publication name.

@jeronimoalbi
Copy link
Member

@mazzy89, I think I got it, with the changes in PR #421 I was able to establish the communication and receive streamed updates

This is required to be container friendly
Also removed tests because right now there are no relevant tests.
@jeronimoalbi jeronimoalbi marked this pull request as ready for review November 3, 2025 14:21
@alanrsoares alanrsoares self-requested a review November 5, 2025 01:14
@alanrsoares alanrsoares self-requested a review November 5, 2025 01:19
Comment on lines 9 to 12
export interface Publisher {
// Publishes a Dither message
publish: (msg: any) => Promise<void>;
}
Copy link
Contributor

@alanrsoares alanrsoares Nov 5, 2025

Choose a reason for hiding this comment

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

Suggested change
export interface Publisher {
// Publishes a Dither message
publish: (msg: any) => Promise<void>;
}
export interface Publisher<T = unknown> {
// Publishes a Dither message
publish: (msg: T) => Promise<void>;
}

Copy link
Contributor

Choose a reason for hiding this comment

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

use a generic interface for better type-safety, any is still possible, but this encourages defining the message type even if it is polymorphic

Copy link
Member

Choose a reason for hiding this comment

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

Changed in 9d5e37d

Comment on lines 15 to 21
export class ConsolePublisher implements Publisher {
async publish(msg: any): Promise<void> {
if (msg) {
logger.info('Post', { msg });
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
export class ConsolePublisher implements Publisher {
async publish(msg: any): Promise<void> {
if (msg) {
logger.info('Post', { msg });
}
}
}
export class ConsolePublisher implements Publisher {
async publish(msg): Promise<void> {
if (msg) {
logger.info('Post', { msg });
}
}
}

here msg is inferred as unknown from the Publisher interface

Copy link
Member

Choose a reason for hiding this comment

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

Changed in 9d5e37d

]),
);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

for the TelegramPublisher, define the PostMessage type and use it for the generic Publisher

Copy link
Member

@jeronimoalbi jeronimoalbi Nov 5, 2025

Choose a reason for hiding this comment

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

In 9d5e37d added an interim type for Post.

I think we should have a generic package that defines the Post type which also has support for sending posts to a Telegram channel. Right now the type is defined in the api-main package, which also implements a sendMessage()

cc @salmad3

@jeronimoalbi
Copy link
Member

jeronimoalbi commented Nov 5, 2025

@mazzy89 I think we need the CI workflows for this app, which could be done in a separate PR

@mazzy89
Copy link
Author

mazzy89 commented Nov 5, 2025

Sure. we can merge and then i will wire everything to release.

@alanrsoares alanrsoares merged commit 6d10d60 into main Nov 5, 2025
11 checks passed
@alanrsoares alanrsoares deleted the feed-sync branch November 5, 2025 20:45
@github-project-automation github-project-automation bot moved this from Ready to Build to Done in Dither Community Board Nov 5, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

Historical Feed Synchronization Service

3 participants