feat: المجموعة H — المواقع في Redis، والقاعدة من الـworker فقط
كان كل نبضة موقع (كل 1-3 ثوانٍ لكل سائق متصل) تكلّف استعلاماً + كتابة صف السائق في Postgres — أثقل حمل كان على القاعدة، وأثقل حتى من سيرو. - H1/H2: نبضة الموقع = Redis فقط، بعتبات سيرو (10م / 1.0 سرعة / 5° اتجاه). سائق واقف = EXPIRE واحد: لا كتابة، لا نقطة مسار، ولا بثّ للراكب - H3: لقطة آخر موقع على drivers (heading/speed/loc_status/loc_updated_at) يكتبها الـworker دورياً. لم نُنشئ جدولاً منفصلاً — drivers أصلاً صف واحد لكل سائق - H4: driver_tracks — تتراكم في قائمة Redis ويُدرجها الـworker بعبارة واحدة - H5: فهرسا available/busy — البحث يمسح المتاحين فقط. السائق يصير busy عند القبول ويعود available عند الإنهاء/الإلغاء - H8: المطابقة والاحتيال و«الرحلات المتاحة» تقرأ الموقع الحيّ من Redis. كشف تزوير الوصول خاصةً يجب ألّا يحكم بلقطة دورية الـworker صار حقيقياً (كان setInterval فارغاً): سياق Nest مستقل، تفريغ كل 5s، قفل يمنع تراكب الدورات، وتفريغة أخيرة عند SIGTERM. مؤجَّل من H: H6 (سلوك السائق) و H7 (ساعات العمل) — تحليلات تُبنى من driver_tracks لاحقاً. هجرة: DriverLocations. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
a83dd7e5e5
commit
0ed3a3160a
@@ -3,7 +3,7 @@ import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { Driver } from './entities/driver.entity';
|
||||
import { UsersService } from '../users/users.service';
|
||||
import { MatchingService } from '../matching/matching.service';
|
||||
import { DriverLocationService } from '../locations/driver-location.service';
|
||||
|
||||
@Injectable()
|
||||
export class DriversService {
|
||||
@@ -11,7 +11,7 @@ export class DriversService {
|
||||
@InjectRepository(Driver)
|
||||
private readonly repo: Repository<Driver>,
|
||||
private readonly users: UsersService,
|
||||
private readonly matching: MatchingService,
|
||||
private readonly locations: DriverLocationService,
|
||||
) {}
|
||||
|
||||
findByUser(tenantId: string, userId: string): Promise<Driver | null> {
|
||||
@@ -62,7 +62,7 @@ export class DriversService {
|
||||
return this.repo.save(driver);
|
||||
}
|
||||
|
||||
/** يبدّل حالة الاتصال؛ عند الاتصال يُضاف لفهرس GEO، وعند الفصل يُزال. */
|
||||
/** يبدّل حالة الاتصال؛ عند الاتصال يدخل فهرس المتاحين، وعند الفصل يُزال. */
|
||||
async setOnline(
|
||||
tenantId: string,
|
||||
userId: string,
|
||||
@@ -72,35 +72,42 @@ export class DriversService {
|
||||
if (!driver) throw new NotFoundException('Driver profile not found');
|
||||
driver.is_online = online;
|
||||
await this.repo.save(driver);
|
||||
if (!online) {
|
||||
await this.matching.removeDriver(tenantId, driver.service_class, driver.id);
|
||||
} else if (driver.last_lat != null && driver.last_lng != null) {
|
||||
await this.matching.addDriver(
|
||||
tenantId,
|
||||
driver.service_class,
|
||||
driver.id,
|
||||
driver.last_lat,
|
||||
driver.last_lng,
|
||||
);
|
||||
}
|
||||
await this.locations.setAvailability(
|
||||
tenantId,
|
||||
driver.id,
|
||||
driver.service_class,
|
||||
online ? 'available' : 'off',
|
||||
);
|
||||
return driver;
|
||||
}
|
||||
|
||||
/** تحديث الموقع الجاري: Redis GEO + لقطة في Postgres. */
|
||||
/**
|
||||
* نبضة موقع — **Redis فقط** (docs/17 — H1). كانت تكتب صف السائق في Postgres
|
||||
* على كل نبضة (كل ثانية/ثلاث لكل سائق متصل) — أثقل حمل كان على القاعدة.
|
||||
* اللقطة الدائمة يكتبها الـworker دورياً.
|
||||
*/
|
||||
async updateLocation(
|
||||
tenantId: string,
|
||||
userId: string,
|
||||
lat: number,
|
||||
lng: number,
|
||||
): Promise<{ ok: boolean }> {
|
||||
extra: { heading?: number; speed?: number } = {},
|
||||
): Promise<{ ok: boolean; significant: boolean }> {
|
||||
const driver = await this.findByUser(tenantId, userId);
|
||||
if (!driver) throw new NotFoundException('Driver profile not found');
|
||||
driver.last_lat = lat;
|
||||
driver.last_lng = lng;
|
||||
await this.repo.save(driver);
|
||||
if (driver.is_online) {
|
||||
await this.matching.addDriver(tenantId, driver.service_class, driver.id, lat, lng);
|
||||
}
|
||||
return { ok: true };
|
||||
if (!driver.is_online) return { ok: true, significant: false };
|
||||
|
||||
const res = await this.locations.update(tenantId, driver.id, driver.service_class, {
|
||||
lat,
|
||||
lng,
|
||||
heading: extra.heading,
|
||||
speed: extra.speed,
|
||||
});
|
||||
return { ok: true, significant: res.significant };
|
||||
}
|
||||
|
||||
/** الموقع الحيّ للسائق — من Redis، واللقطة احتياط. */
|
||||
liveLocation(tenantId: string, driverId: string) {
|
||||
return this.locations.get(tenantId, driverId);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user