mirror of
				https://github.com/3ybactuk/marketplace-go-service-project.git
				synced 2025-10-31 06:23:44 +03:00 
			
		
		
		
	[hw-6] add notifier service, kafka
This commit is contained in:
		
							
								
								
									
										11
									
								
								loms/internal/domain/repository/outbox/outbox_event.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								loms/internal/domain/repository/outbox/outbox_event.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| package outbox | ||||
|  | ||||
| import "route256/loms/internal/domain/entity" | ||||
|  | ||||
| type Event struct { | ||||
| 	ID      int64 | ||||
| 	OrderID entity.ID | ||||
| 	Topic   string | ||||
| 	Key     string | ||||
| 	Payload []byte | ||||
| } | ||||
							
								
								
									
										32
									
								
								loms/internal/domain/repository/outbox/sqlc/db.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								loms/internal/domain/repository/outbox/sqlc/db.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| // Code generated by sqlc. DO NOT EDIT. | ||||
| // versions: | ||||
| //   sqlc v1.29.0 | ||||
|  | ||||
| package sqlc | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
|  | ||||
| 	"github.com/jackc/pgx/v5" | ||||
| 	"github.com/jackc/pgx/v5/pgconn" | ||||
| ) | ||||
|  | ||||
| type DBTX interface { | ||||
| 	Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error) | ||||
| 	Query(context.Context, string, ...interface{}) (pgx.Rows, error) | ||||
| 	QueryRow(context.Context, string, ...interface{}) pgx.Row | ||||
| } | ||||
|  | ||||
| func New(db DBTX) *Queries { | ||||
| 	return &Queries{db: db} | ||||
| } | ||||
|  | ||||
| type Queries struct { | ||||
| 	db DBTX | ||||
| } | ||||
|  | ||||
| func (q *Queries) WithTx(tx pgx.Tx) *Queries { | ||||
| 	return &Queries{ | ||||
| 		db: tx, | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										5
									
								
								loms/internal/domain/repository/outbox/sqlc/models.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								loms/internal/domain/repository/outbox/sqlc/models.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| // Code generated by sqlc. DO NOT EDIT. | ||||
| // versions: | ||||
| //   sqlc v1.29.0 | ||||
|  | ||||
| package sqlc | ||||
							
								
								
									
										18
									
								
								loms/internal/domain/repository/outbox/sqlc/querier.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								loms/internal/domain/repository/outbox/sqlc/querier.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| // Code generated by sqlc. DO NOT EDIT. | ||||
| // versions: | ||||
| //   sqlc v1.29.0 | ||||
|  | ||||
| package sqlc | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| ) | ||||
|  | ||||
| type Querier interface { | ||||
| 	OutboxInsert(ctx context.Context, arg *OutboxInsertParams) error | ||||
| 	OutboxMarkError(ctx context.Context, dollar_1 []int64) (int64, error) | ||||
| 	OutboxMarkSent(ctx context.Context, dollar_1 []int64) (int64, error) | ||||
| 	OutboxSelectForPublish(ctx context.Context, limit int32) ([]*OutboxSelectForPublishRow, error) | ||||
| } | ||||
|  | ||||
| var _ Querier = (*Queries)(nil) | ||||
							
								
								
									
										22
									
								
								loms/internal/domain/repository/outbox/sqlc/query.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								loms/internal/domain/repository/outbox/sqlc/query.sql
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| -- name: OutboxInsert :exec | ||||
| INSERT INTO outbox (order_id, topic, "key", payload) | ||||
| VALUES ($1, $2, $3, $4::jsonb); | ||||
|  | ||||
| -- name: OutboxSelectForPublish :many | ||||
| SELECT id, order_id, topic, "key", payload | ||||
| FROM   outbox | ||||
| WHERE  status = 'new' | ||||
| ORDER  BY created_at | ||||
| LIMIT  $1 | ||||
| FOR UPDATE SKIP LOCKED; | ||||
|  | ||||
| -- name: OutboxMarkSent :execrows | ||||
| UPDATE outbox | ||||
| SET    status  = 'sent', | ||||
|        sent_at = now() | ||||
| WHERE  id = ANY($1::bigint[]); | ||||
|  | ||||
| -- name: OutboxMarkError :execrows | ||||
| UPDATE outbox | ||||
| SET    status = 'error' | ||||
| WHERE  id = ANY($1::bigint[]); | ||||
							
								
								
									
										104
									
								
								loms/internal/domain/repository/outbox/sqlc/query.sql.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								loms/internal/domain/repository/outbox/sqlc/query.sql.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,104 @@ | ||||
| // Code generated by sqlc. DO NOT EDIT. | ||||
| // versions: | ||||
| //   sqlc v1.29.0 | ||||
| // source: query.sql | ||||
|  | ||||
| package sqlc | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| ) | ||||
|  | ||||
| const outboxInsert = `-- name: OutboxInsert :exec | ||||
| INSERT INTO outbox (order_id, topic, "key", payload) | ||||
| VALUES ($1, $2, $3, $4::jsonb) | ||||
| ` | ||||
|  | ||||
| type OutboxInsertParams struct { | ||||
| 	OrderID int64 | ||||
| 	Topic   string | ||||
| 	Key     *string | ||||
| 	Column4 []byte | ||||
| } | ||||
|  | ||||
| func (q *Queries) OutboxInsert(ctx context.Context, arg *OutboxInsertParams) error { | ||||
| 	_, err := q.db.Exec(ctx, outboxInsert, | ||||
| 		arg.OrderID, | ||||
| 		arg.Topic, | ||||
| 		arg.Key, | ||||
| 		arg.Column4, | ||||
| 	) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| const outboxMarkError = `-- name: OutboxMarkError :execrows | ||||
| UPDATE outbox | ||||
| SET    status = 'error' | ||||
| WHERE  id = ANY($1::bigint[]) | ||||
| ` | ||||
|  | ||||
| func (q *Queries) OutboxMarkError(ctx context.Context, dollar_1 []int64) (int64, error) { | ||||
| 	result, err := q.db.Exec(ctx, outboxMarkError, dollar_1) | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| 	return result.RowsAffected(), nil | ||||
| } | ||||
|  | ||||
| const outboxMarkSent = `-- name: OutboxMarkSent :execrows | ||||
| UPDATE outbox | ||||
| SET    status  = 'sent', | ||||
|        sent_at = now() | ||||
| WHERE  id = ANY($1::bigint[]) | ||||
| ` | ||||
|  | ||||
| func (q *Queries) OutboxMarkSent(ctx context.Context, dollar_1 []int64) (int64, error) { | ||||
| 	result, err := q.db.Exec(ctx, outboxMarkSent, dollar_1) | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| 	return result.RowsAffected(), nil | ||||
| } | ||||
|  | ||||
| const outboxSelectForPublish = `-- name: OutboxSelectForPublish :many | ||||
| SELECT id, order_id, topic, "key", payload | ||||
| FROM   outbox | ||||
| WHERE  status = 'new' | ||||
| ORDER  BY created_at | ||||
| LIMIT  $1 | ||||
| FOR UPDATE SKIP LOCKED | ||||
| ` | ||||
|  | ||||
| type OutboxSelectForPublishRow struct { | ||||
| 	ID      int64 | ||||
| 	OrderID int64 | ||||
| 	Topic   string | ||||
| 	Key     *string | ||||
| 	Payload []byte | ||||
| } | ||||
|  | ||||
| func (q *Queries) OutboxSelectForPublish(ctx context.Context, limit int32) ([]*OutboxSelectForPublishRow, error) { | ||||
| 	rows, err := q.db.Query(ctx, outboxSelectForPublish, limit) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defer rows.Close() | ||||
| 	var items []*OutboxSelectForPublishRow | ||||
| 	for rows.Next() { | ||||
| 		var i OutboxSelectForPublishRow | ||||
| 		if err := rows.Scan( | ||||
| 			&i.ID, | ||||
| 			&i.OrderID, | ||||
| 			&i.Topic, | ||||
| 			&i.Key, | ||||
| 			&i.Payload, | ||||
| 		); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		items = append(items, &i) | ||||
| 	} | ||||
| 	if err := rows.Err(); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return items, nil | ||||
| } | ||||
							
								
								
									
										85
									
								
								loms/internal/domain/repository/outbox/sqlc/repository.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								loms/internal/domain/repository/outbox/sqlc/repository.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,85 @@ | ||||
| package sqlc | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
|  | ||||
| 	"github.com/jackc/pgx/v5/pgxpool" | ||||
|  | ||||
| 	"route256/loms/internal/domain/entity" | ||||
| 	"route256/loms/internal/domain/repository/outbox" | ||||
| 	"route256/loms/internal/infra/postgres" | ||||
| ) | ||||
|  | ||||
| type outboxRepo struct { | ||||
| 	db *pgxpool.Pool | ||||
| } | ||||
|  | ||||
| func NewOutboxRepository(masterPool *pgxpool.Pool) *outboxRepo { | ||||
| 	return &outboxRepo{ | ||||
| 		db: masterPool, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (r *outboxRepo) GetQuerier(ctx context.Context) *Queries { | ||||
| 	tx, ok := postgres.TxFromCtx(ctx) | ||||
| 	if ok { | ||||
| 		return New(tx) | ||||
| 	} | ||||
|  | ||||
| 	return New(r.db) | ||||
| } | ||||
|  | ||||
| func (r *outboxRepo) AddEvent(ctx context.Context, evt outbox.Event) error { | ||||
| 	querier := r.GetQuerier(ctx) | ||||
|  | ||||
| 	return querier.OutboxInsert(ctx, &OutboxInsertParams{ | ||||
| 		OrderID: int64(evt.OrderID), | ||||
| 		Topic:   evt.Topic, | ||||
| 		Key:     &evt.Key, | ||||
| 		Column4: evt.Payload, | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func (r *outboxRepo) WithNewEvents(ctx context.Context, limit int32, handler func(context.Context, outbox.Event) error) error { | ||||
| 	querier := r.GetQuerier(ctx) | ||||
|  | ||||
| 	rows, err := querier.OutboxSelectForPublish(ctx, int32(limit)) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if len(rows) == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	var sentIDs, errIDs []int64 | ||||
|  | ||||
| 	for _, row := range rows { | ||||
| 		ev := outbox.Event{ | ||||
| 			ID:      row.ID, | ||||
| 			OrderID: entity.ID(row.OrderID), | ||||
| 			Topic:   row.Topic, | ||||
| 			Key:     *row.Key, | ||||
| 			Payload: row.Payload, | ||||
| 		} | ||||
|  | ||||
| 		if err := handler(ctx, ev); err != nil { | ||||
| 			errIDs = append(errIDs, row.ID) | ||||
| 		} else { | ||||
| 			sentIDs = append(sentIDs, row.ID) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if len(sentIDs) > 0 { | ||||
| 		if _, err := querier.OutboxMarkSent(ctx, sentIDs); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if len(errIDs) > 0 { | ||||
| 		if _, err := querier.OutboxMarkError(ctx, errIDs); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Никита Шубин
					Никита Шубин