Browse Source

Merge c249a916d2 into a463b5511b

pull/6711/merge
Asish Kumar 2 days ago
committed by GitHub
parent
commit
5430acc126
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 1
      CHANGELOG.md
  2. 4
      README.md
  3. 7
      apps/api/src/app/app.module.ts
  4. 12
      apps/api/src/app/redis-cache/redis-cache.module.ts
  5. 74
      apps/api/src/helper/redis-options.helper.spec.ts
  6. 65
      apps/api/src/helper/redis-options.helper.ts

1
CHANGELOG.md

@ -44,6 +44,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
- Fixed Redis and Valkey connectivity when `REDIS_HOST` points to a Unix socket
- Improved the style of the activity type component
## 2.253.0 - 2026-03-06

4
README.md

@ -100,9 +100,9 @@ We provide official container images hosted on [Docker Hub](https://hub.docker.c
| `POSTGRES_PASSWORD` | `string` | | The password of the _PostgreSQL_ database |
| `POSTGRES_USER` | `string` | | The user of the _PostgreSQL_ database |
| `REDIS_DB` | `number` (optional) | `0` | The database index of _Redis_ |
| `REDIS_HOST` | `string` | | The host where _Redis_ is running |
| `REDIS_HOST` | `string` | | The host or Unix socket path where _Redis_ is running |
| `REDIS_PASSWORD` | `string` | | The password of _Redis_ |
| `REDIS_PORT` | `number` | | The port where _Redis_ is running |
| `REDIS_PORT` | `number` | | The port where _Redis_ is running (ignored when `REDIS_HOST` is a Unix socket path) |
| `REQUEST_TIMEOUT` | `number` (optional) | `2000` | The timeout of network requests to data providers in milliseconds |
| `ROOT_URL` | `string` (optional) | `http://0.0.0.0:3333` | The root URL of the Ghostfolio application, used for generating callback URLs and external links. |

7
apps/api/src/app/app.module.ts

@ -1,4 +1,5 @@
import { EventsModule } from '@ghostfolio/api/events/events.module';
import { getBullRedisOptions } from '@ghostfolio/api/helper/redis-options.helper';
import { BullBoardAuthMiddleware } from '@ghostfolio/api/middlewares/bull-board-auth.middleware';
import { HtmlTemplateMiddleware } from '@ghostfolio/api/middlewares/html-template.middleware';
import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module';
@ -98,12 +99,12 @@ import { UserModule } from './user/user.module';
]
: []),
BullModule.forRoot({
redis: {
redis: getBullRedisOptions({
db: parseInt(process.env.REDIS_DB ?? '0', 10),
host: process.env.REDIS_HOST,
host: process.env.REDIS_HOST ?? 'localhost',
password: process.env.REDIS_PASSWORD,
port: parseInt(process.env.REDIS_PORT ?? '6379', 10)
}
})
}),
CacheModule,
ConfigModule.forRoot(),

12
apps/api/src/app/redis-cache/redis-cache.module.ts

@ -1,3 +1,4 @@
import { getKeyvRedisOptions } from '@ghostfolio/api/helper/redis-options.helper';
import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module';
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
@ -14,14 +15,15 @@ import { RedisCacheService } from './redis-cache.service';
imports: [ConfigurationModule],
inject: [ConfigurationService],
useFactory: async (configurationService: ConfigurationService) => {
const redisPassword = encodeURIComponent(
configurationService.get('REDIS_PASSWORD')
);
return {
stores: [
createKeyv(
`redis://${redisPassword ? `:${redisPassword}` : ''}@${configurationService.get('REDIS_HOST')}:${configurationService.get('REDIS_PORT')}/${configurationService.get('REDIS_DB')}`
getKeyvRedisOptions({
db: configurationService.get('REDIS_DB'),
host: configurationService.get('REDIS_HOST'),
password: configurationService.get('REDIS_PASSWORD'),
port: configurationService.get('REDIS_PORT')
})
)
],
ttl: configurationService.get('CACHE_TTL')

74
apps/api/src/helper/redis-options.helper.spec.ts

@ -0,0 +1,74 @@
import {
getBullRedisOptions,
getKeyvRedisOptions
} from './redis-options.helper';
describe('getBullRedisOptions', () => {
it('should return tcp options when using a hostname', () => {
expect(
getBullRedisOptions({
db: 2,
host: 'localhost',
password: 'secret',
port: 6380
})
).toStrictEqual({
db: 2,
host: 'localhost',
password: 'secret',
port: 6380
});
});
it('should return unix socket options when using a socket path', () => {
expect(
getBullRedisOptions({
db: 0,
host: '/run/valkey/valkey.sock',
password: '',
port: 6379
})
).toStrictEqual({
db: 0,
password: undefined,
path: '/run/valkey/valkey.sock'
});
});
});
describe('getKeyvRedisOptions', () => {
it('should return tcp options when using a hostname', () => {
expect(
getKeyvRedisOptions({
db: 1,
host: 'redis',
password: 'secret',
port: 6379
})
).toStrictEqual({
database: 1,
password: 'secret',
socket: {
host: 'redis',
port: 6379
}
});
});
it('should return unix socket options when using a socket path', () => {
expect(
getKeyvRedisOptions({
db: 5,
host: '/var/run/redis/redis.sock',
password: '',
port: 6379
})
).toStrictEqual({
database: 5,
password: undefined,
socket: {
path: '/var/run/redis/redis.sock'
}
});
});
});

65
apps/api/src/helper/redis-options.helper.ts

@ -0,0 +1,65 @@
import type { RedisClientOptions } from '@keyv/redis';
import type { RedisOptions } from 'ioredis';
interface RedisConnectionOptions {
db: number;
host: string;
password?: string;
port: number;
}
export function getBullRedisOptions({
db,
host,
password,
port
}: RedisConnectionOptions): RedisOptions {
const redisPassword = password || undefined;
if (isUnixSocketPath(host)) {
return {
db,
password: redisPassword,
path: host
};
}
return {
db,
host,
password: redisPassword,
port
};
}
export function getKeyvRedisOptions({
db,
host,
password,
port
}: RedisConnectionOptions): RedisClientOptions {
const redisPassword = password || undefined;
if (isUnixSocketPath(host)) {
return {
database: db,
password: redisPassword,
socket: {
path: host
}
};
}
return {
database: db,
password: redisPassword,
socket: {
host,
port
}
};
}
function isUnixSocketPath(host: string) {
return host.startsWith('/');
}
Loading…
Cancel
Save