Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 60 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ jobs:
- os: linux
runs-on: ubuntu-latest
arch: x86_64
- os: linux-musl
runs-on: ubuntu-latest
arch: x86_64
steps:
- name: Checkout code
uses: actions/checkout@v4
Expand All @@ -48,6 +51,15 @@ jobs:
sudo apt-get update
sudo apt-get install -y sqlite3 libsqlite3-dev build-essential

- name: Install dependencies (Alpine/musl)
if: matrix.os == 'linux-musl'
run: |
# Use Alpine container for musl builds
docker run --rm -v ${{ github.workspace }}:/workspace -w /workspace alpine:latest sh -c "
apk add --no-cache build-base sqlite-dev go curl git &&
echo 'Alpine dependencies installed'
"

- name: Install dependencies (macOS)
if: matrix.os == 'darwin'
run: |
Expand All @@ -59,7 +71,7 @@ jobs:
choco install sqlite

- name: Build SQLite (Unix)
if: matrix.os != 'windows'
if: matrix.os != 'windows' && matrix.os != 'linux-musl'
run: |
cd sqlite
if [ ! -d "sqlite-latest" ]; then
Expand All @@ -73,6 +85,24 @@ jobs:
make
make install

- name: Build SQLite (Alpine/musl)
if: matrix.os == 'linux-musl'
run: |
# Build SQLite in Alpine container for musl compatibility
docker run --rm -v ${{ github.workspace }}:/workspace -w /workspace alpine:latest sh -c "
apk add --no-cache build-base curl &&
cd sqlite &&
if [ ! -d 'sqlite-latest' ]; then
curl -O https://www.sqlite.org/2024/sqlite-autoconf-3450100.tar.gz
tar xzf sqlite-autoconf-3450100.tar.gz
mv sqlite-autoconf-3450100 sqlite-latest
fi &&
cd sqlite-latest &&
./configure --prefix=\$(pwd)/../install --enable-static --disable-shared 'CFLAGS=-DSQLITE_ENABLE_DBPAGE_VTAB=1 -O2' &&
make &&
make install
"

- name: Build SQLite (Windows)
if: matrix.os == 'windows'
run: |
Expand All @@ -89,10 +119,21 @@ jobs:
bash -c "make install"

- name: Build Bridge
if: matrix.os != 'linux-musl'
run: |
cd bridge
make

- name: Build Bridge (Alpine/musl)
if: matrix.os == 'linux-musl'
run: |
# Build bridge in Alpine container
docker run --rm -v ${{ github.workspace }}:/workspace -w /workspace alpine:latest sh -c "
apk add --no-cache build-base go &&
cd bridge &&
make
"

- name: Set build environment (Darwin ARM64)
if: matrix.os == 'darwin' && matrix.arch == 'arm64'
run: |
Expand All @@ -114,6 +155,13 @@ jobs:
echo "GOARCH=amd64" >> $GITHUB_ENV
echo "CGO_ENABLED=1" >> $GITHUB_ENV

- name: Set build environment (Linux musl x86_64)
if: matrix.os == 'linux-musl' && matrix.arch == 'x86_64'
run: |
echo "GOOS=linux" >> $GITHUB_ENV
echo "GOARCH=amd64" >> $GITHUB_ENV
echo "CGO_ENABLED=1" >> $GITHUB_ENV

- name: Set build environment (Windows)
if: matrix.os == 'windows'
run: |
Expand All @@ -122,11 +170,21 @@ jobs:
echo "CGO_ENABLED=1" >> $env:GITHUB_ENV

- name: Build Client (Unix)
if: matrix.os != 'windows'
if: matrix.os != 'windows' && matrix.os != 'linux-musl'
run: |
cd client
make build

- name: Build Client (Alpine/musl)
if: matrix.os == 'linux-musl'
run: |
# Build client in Alpine container
docker run --rm -v ${{ github.workspace }}:/workspace -w /workspace alpine:latest sh -c "
apk add --no-cache build-base go git &&
cd client &&
make build
"

- name: Build Client (Windows)
if: matrix.os == 'windows'
run: |
Expand Down
2 changes: 1 addition & 1 deletion client/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
"github.com/sqlrsync/sqlrsync.com/sync"
)

var VERSION = "0.0.6"
var VERSION = "0.0.9"
var (
serverURL string
verbose bool
Expand Down
25 changes: 20 additions & 5 deletions client/remote/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -1455,14 +1455,29 @@ func (c *Client) writeLoop() {
err := conn.WriteMessage(websocket.BinaryMessage, data)
if err != nil {
c.logger.Error("WebSocket write error", zap.Error(err))

// If the error indicates we already sent a close, treat this as a normal
// closure for PUSH syncs and mark the sync completed so the caller can
// finish processing. This happens when the websocket library returns
// "websocket: close sent" while attempting to write after a close.
if strings.Contains(err.Error(), "close sent") {
c.logger.Info("Write error contains 'close sent' - treating as normal closure")
c.logger.Info("Ending PUSH sync due to close-sent write error")
c.setSyncCompleted(true)
}
c.setError(err)
c.setConnected(false)

// Signal potential reconnection
select {
case c.reconnectChan <- struct{}{}:
default:
}
// Treat this as a true disconnection (do not trigger reconnect).
// Close the read queue so any readers observe EOF and stop.
func() {
defer func() {
if r := recover(); r != nil {
// ignore if already closed
}
}()
close(c.readQueue)
}()
return
}

Expand Down
2 changes: 1 addition & 1 deletion client/sync/coordinator.go
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ func (c *Coordinator) executePull(isSubscription bool) error {
AuthKey: authResult.AccessKey,
ReplicaID: authResult.ReplicaID,
Timeout: 8000,
PingPong: false, // No ping/pong needed for single sync
PingPong: true, // Ping/pong enabled for subscription sync
Logger: c.logger.Named("remote"),
Subscribe: false, // Subscription handled separately
EnableTrafficInspection: c.config.Verbose,
Expand Down
Loading