Skip to Content

Veri Arka Ucu

IronFlock, TimescaleDB tarafından desteklenen her proje için özel bir veritabanı sağlar. Uygulamanız veri şemasını tanımlar; IronFlock tabloları oluşturur ve uygulamaya bir cihaz eklenir eklenmez veri toplamaya başlar.

Nasıl Çalışır

  1. Veri şemanızı .ironflock/data-template.yml içinde tanımlayın.
  2. Edge kodunuzdan veri yayımlamak için IronFlock SDK’sını kullanın.
  3. IronFlock, uygulamanın kurulu olduğu her projedeki veritabanı tablolarını otomatik olarak ayarlar.
  4. Veriler cihazlardan mesajlaşma sistemi aracılığıyla proje veritabanına akar.

Her proje kendi fiziksel veritabanını alır — projeler arasında veri paylaşımı yoktur.

Kullanıcı, projelerinde uygulamanız tarafından toplanan veriler üzerinde tam kontrole sahiptir. Geliştirici olarak bu verilere erişiminiz yoktur.

Veri Şemasını Tanımlama

.ironflock/ dizininde bir data-template.yml dosyası oluşturun:

data: tables: - tablename: sensordata columns: - id: tsp name: Timestamp description: Timestamp of measurement path: args[0].timestamp dataType: timestamp - id: temperature name: Temperature description: Temperature reading in Celsius path: args[0].temperature dataType: numeric - id: humidity name: Humidity description: Relative humidity percentage path: args[0].humidity dataType: numeric - id: device_id name: Device ID description: Source device identifier path: args[0].device_id dataType: string

Sütun Seçenekleri

AlanAçıklama
idİç sütun tanımlayıcısı (zaman damgası sütunları için tsp kullanın)
namePanolarda gösterilen, okunabilir sütun adı
descriptionİsteğe bağlı açıklama
pathYayımlanan veri nesnesindeki değerin yolu (örn. args[0].temperature)
dataTypeŞunlardan biri: timestamp, numeric, string, boolean
secretBu sütunu şifrelenmiş olarak saklar ve normal bir okumada asla açık şekilde döndürmez — aşağıdaki Gizli Sütunlar bölümüne bakın

Gizli Sütunlar

Bazı değerlerin saklanması gerekir ama asla gösterilmemelidir: bir API belirteci, bir cihaz parolası, bir lisans anahtarı. Sütunu secret: true ile işaretleyin; veri arka ucu onu ekleme sırasında şifreler:

- tablename: credentials columns: - id: tsp dataType: timestamp - id: device_id dataType: string - id: api_token dataType: string secret: true

Bundan sonra hiçbir olağan okuma düz metni döndürmez — onu yazan uygulamaya bile:

Okuma yoluGeri aldığınız şey
Geçmiş okumaları ve gerçek zamanlı satırlar: panoların, widget’ların, SDK’nın ve tabloyu okuyan diğer uygulamaların aldığı şey__secret__ yer tutucusu
SQL (SQL sorgu konsolu, veri dışa aktarımları ve FleetDB Access Postgres oturumu) ve veritabanı yedeklerisaklanan şifreli metin, ifsec:1:…
SDK’nın açığa çıkarma fonksiyonuşifresi çözülmüş değer

NULL her yerde NULL olarak kalır; böylece “atanmış ama gizli” ile “hiç yazılmamış” birbirinden ayırt edilebilir kalır.

Bir sırrı açık şekilde geri okumak yalnızca uygulamanın kendi kapsayıcılarından, SDK aracılığıyla mümkündür — SDK referansındaki Gizli Sütunlar bölümüne bakın. Panolar ve diğer uygulamalar bu değeri hiçbir şekilde elde edemez; “asla açık şekilde gösterilmez” ifadesini yalnızca göstermelik değil de gerçek kılan budur.

Bir satırı sırrını kaybetmeden güncelleme. Bir varlık tablosunda, bir satırı düzenleyen istemci gerçek sırrı asla geri gönderemez — okumalar ona yalnızca yer tutucuyu vermiştir. Bu nedenle veri arka ucu, yazma sırasında __secret__ yer tutucusunu (ve panoların gösterdiği •••••••• maskesini) önceki değeri koru olarak yorumlar; atlanan bir gizli sütun da değeri korur. Açıkça null göndermek sırrı temizler. Dolayısıyla bir pano formunda bir makinenin açıklamasını düzenlemek, erişim kodunu asla silmez.

Bundan iki sonuç çıkar: __secret__ ve •••••••• sabit dizeleri kendileri gizli değer olarak saklanamaz (ve ham ifsec:… şifreli metni girdi olarak reddedilir) ve varlık anahtarı olmayan bir tabloda yer tutucu yazımı reddedilir — korunacak önceki bir satır yoktur.

Baştan planlamaya değer üç sonuç vardır, çünkü bunlar birer öneri değil kesin sınırlardır:

  • Gizli sütunlar yalnızca dize (string) olabilir. Şifreleme metin ürettiği için numeric, boolean ve timestamp sütunları gizli olamaz. Zorunlu tsp sütunu da gizli olamaz.
  • Bir gizli sütuna göre filtreleme, gruplama veya sıralama yapamazsınız. Her satır kendi rastgele değeriyle şifrelenir; dolayısıyla aynı sırrı tutan iki satır farklı şifreli metin saklar. Bir gizli sütun üzerinde eşitlik filtreleri, GROUP BY, ORDER BY ve DISTINCT düpedüz çalışamaz. “Bu değer eşleşiyor mu?” sorusunu yanıtlamak için, herhangi bir şey döndürmek yerine karşılaştırmayı veri arka ucunun içinde yapan SDK’nın doğrulama fonksiyonunu kullanın.
  • Bir gizli sütun varlık anahtarı olamaz. Her satırın şifreli metni farklı olduğundan, varlık başına en son satırı veren okumalar her satırı ayrı bir varlık sayardı; bu nedenle böyle bir sütunun maintainLatestFlagFor içinde adlandırılması doğrudan reddedilir.

Son iki kısıtlama, veri şablonunuz doğrulanırken denetlenir; dolayısıyla bunları ihlal eden bir tablo, sonradan hatalı davranmak yerine yayımlama sırasında başarısız olur.

Tablo Seçenekleri

columns dışında bir tablo, nasıl tanımlandığını ve verisinin nasıl yaşlandığını denetleyen birkaç isteğe bağlı anahtar kabul eder:

data: tables: - tablename: sensordata description: Üretim sahasından ortam ölçümleri chunkTimeInterval: 1 hour dropAfter: 30 days columns: # ...
AlanAçıklama
tablenameTablonun adı
descriptionİsteğe bağlı açıklama; arayüzde gösterilir ve yapay zekâ ajanları tarafından tabloyu anlamak için kullanılır
chunkTimeIntervalTablonun bölündüğü zaman bölümlerinin boyutu. Varsayılan 7 days
dropAfterSaklama penceresi — bundan eski bölümler otomatik olarak silinir
downsampleUzun pencereli grafiklerin hızlı çalışması için önceden toplulaştırılmış bir kopya tutar — aşağıdaki Sürekli Aşağı Örnekleme bölümüne bakın
maintainLatestFlagForBenzersiz bir varlığı tanımlayan sütunlar — aşağıdaki Bir Varlığın En Son Durumunu Takip Etme bölümüne bakın
privateBu tabloyu diğer uygulamalardan gizler — aşağıdaki Verileri Diğer Uygulamalarla Paylaşma bölümüne bakın

chunkTimeInterval, zaman serisi verisinin diskte nasıl bölümleneceğini belirler. Bir bölümün, tek seferde sorguladığınız veri miktarına yaklaşık olarak denk gelmesini sağlayacak bir değer seçin: saniyede bir toplanan yüksek frekanslı veriler küçük parçalardan (dakikalar–saatler), yavaş değişen veriler ise büyük parçalardan (haftalar) fayda görür. Bu yalnızca uygulamanın varsayılanıdır — proje sahibi daha sonra kendi data backend’inde bunu değiştirebilir.

dropAfter, tabloyu kayan bir pencereye dönüştürür. Belirtilen aralıktan eski bölümler bütün olarak silinir; bu, satırları tek tek silmekten çok daha ucuzdur. Temizleme işi dropAfter / 4 aralığıyla çalışır, dolayısıyla bir kayıt bölümü kaldırılana kadar süresini aralığın dörtte biri kadar aşabilir. Verileri süresiz saklamak için dropAfter’ı belirtmeyin.

Her ikisi de PostgreSQL aralık ifadeleri alır — 30 minutes, 1 hour, 7 days, 6 months.

Sürekli Aşağı Örnekleme

Panolar, veritabanından veriyi toplulaştırmasını isteyebilir — saatlik ortalamalar, günlük toplamlar, makine başına sayımlar. Bunları ham kayıtlardan hesaplamak bir gün için sorunsuzdur, bir yıl için pahalıdır. Bir tabloya downsample ekleyin; platform o tablonun sürekli güncellenen, önceden toplulaştırılmış bir kopyasını tutar ve uzun pencereli sorguları bunun yerine o kopyadan yanıtlar:

data: tables: - tablename: sensordata dropAfter: 30 days downsample: bucket: 1 minute keepFor: 2 years paths: - payload.temperature columns: # ...
AlanAçıklama
bucketÖnceden toplulaştırılmış kopyanın çözünürlüğü. Varsayılan 1 minute
keepForAşağı örneklenmiş geçmişin ne kadar saklanacağı. Süresiz saklamak için belirtmeyin
pathsDahil edilecek JSON alan yolları; panoların kullandığı gösterimin aynısı

bucket, bir grafiğin sunulabileceği en ince çözünürlüktür — bundan çok daha ince aralıklar isteyen bir grafik onun yerine ham tabloyu okur. Bir günü tam bölen, 1 second ile 1 day arasındaki sabit genişlikli aralıkları kabul eder (1 minute, 5 minutes, 1 hour). Varsayılan 1 minute pratikte her panoya uygundur; daha kaba bir aralık daha az depolama ve daha az yazma yükü demektir.

keepFor, uzun geçmişleri en baştan mümkün kılan şeydir. Ham kayıtlar dropAfter ile silinir, ancak aşağı örneklenmiş kopyanın kendi saklama süresi vardır: ham veriyi 30 gün, aşağı örneklenmiş veriyi 2 yıl saklayın; bir pano depolamanın küçük bir bölümüyle yine de iki yıllık saatlik ortalamaları grafikleyebilir. Bunu dropAfter’dan daha uzun ayarlayın — platform tersini hatalı yapılandırma sayarak reddeder.

paths, aşağı örneklemeyi JSON sütunlarının içindeki değerlere de genişletir. Sayısal sütunlar otomatik olarak dahil edilir; JSON alanlarının ise açıkça adlandırılması gerekir, çünkü bir JSON sütununun sabit bir anahtar kümesi yoktur. Bildirilmemiş alanlar panolarda yine de çalışır — yalnızca ham tablodan hesaplanırlar.

Geri kalan her şey otomatiktir. Her sayısal sütunun istatistikleri (ortalama, toplam, minimum, maksimum, ilk, son ve kayıt sayısı), tablonun varlık anahtarına (maintainLatestFlagFor ya da yayımlayan cihaz) göre gruplanarak sürdürülür. Panoların ne bir yapılandırmaya ne de bundan haberdar olmaya ihtiyacı vardır: widget her zamanki gibi sorgular ve platform her sorguda önceden toplulaştırılmış kopyanın yanıt verip veremeyeceğine karar verir — veremediğinde, örneğin bir filtre kopyanın gruplamadığı bir sütuna atıfta bulunduğunda, şeffaf biçimde ham tabloya geri düşer.

Şema değişiklikleri kopyayı yeniden oluşturur. Aşağı örneklenmiş bir tabloya sütun eklemek, sütun kaldırmak veya bir sütunun tipini değiştirmek — ya da downsample bloğunun kendisini düzenlemek — önceden toplulaştırılmış kopyayı ham tablodan yeniden oluşturur. dropAfter’dan eski olan hiçbir şey yeniden kurulamaz ve kaybolur. Bu bloğu mümkün olduğunca tabloyla birlikte kurun ve uzun ömürlü tablolardaki sonraki şema değişikliklerini bilinçli bir karar olarak ele alın.

Edge Kodundan Veri Yayımlama

Uygulamanızdan veri göndermek için IronFlock SDK’sını kullanın:

from ironflock import IronFlock flock = IronFlock() await flock.start() await flock.publish_to_table("sensordata", { "timestamp": "2025-01-15T10:30:00Z", "temperature": 23.5, "humidity": 62.1, "device_id": "sensor-001" })

Her satırın zorunlu tsp sütunu için bir değere ihtiyacı vardır: veri arka ucu bu değeri içermeyen bir satırı reddeder. SDK’nın tablo yazması bir hatayla başarısız olur; bir panonun yayımladığı satır ise atılır ve uygulamanın error-logs tablosunda yalnızca bir kayıt bırakır. Yukarıdaki sensordata tanımı bu sütunu path: args[0].timestamp ile eşler; bu nedenle tsp, satırın timestamp alanından gelir. path içermeyen bir sütun, satırdaki aynı adlı alanı (args[0].<id>) okur: bu eşleme olmasaydı her satırın kendi tsp alanına ihtiyacı olurdu.

Yüksek frekanslı veriler için, satır başına bir gidiş-dönüş yerine publish_rows_to_table / publishRowsToTable / PublishRowsToTable ya da append_rows_to_table / appendRowsToTable / AppendRowsToTable kullanarak tek bir mesajda birden çok satır gönderin — ikisi aynıdır ve ekleme sonucunu bildirir. Her yığın atomik olarak eklenir — ya hep ya hiç. Ayrıntılar için bkz. SDK referansı.

Dönüşüm Tabloları

Ham verilerinizi otomatik olarak toplayan veya işleyen SQL dönüşümleri tanımlayabilirsiniz:

data: tables: - tablename: sensordata columns: # ... ham veri sütunları ... transforms: - tablename: hourly_averages materialize: true schedule: "0 * * * *" sql: > SELECT time_bucket('1 hour', tsp) AS hour, avg(temperature) AS avg_temp, avg(humidity) AS avg_humidity FROM sensordata GROUP BY hour columns: - id: hour name: Hour dataType: timestamp - id: avg_temp name: Average Temperature dataType: numeric - id: avg_humidity name: Average Humidity dataType: numeric
AlanAçıklama
tablenameTüretilmiş tablonun adı
materializetrue ise sonuç saklanır ve zamanlamaya göre tazelenir. false ise dönüşüm, her okumada hesaplanan bir görünümdür
scheduleDönüşümün çalıştırmaları için cron ifadesi: beş alan (dakika, saat, ayın günü, ay, haftanın günü) ya da başına saniye alanı eklenmiş altı alan. */5 * * * * her 5 dakikada, */10 * * * * * her 10 saniyede bir çalışır. Her çalıştırma kalıcılaştırılmış sonucu tazeler ve güncel sonucu dönüşüme bağlı panolara gönderir. Uygulamanın kodu böyle bir çalıştırmayı talep üzerine de yapabilir, bkz. Talep Üzerine Tazeleme
sqlDönüşümü hesaplayan SQL sorgusu
columnsÇıktı için sütun tanımları

Dönüşüm tabloları, tıpkı normal tablolar gibi panolarda ve SDK aracılığıyla erişilebilir.

Bir dönüşüm tam olarak kendi SQL’inin döndürdüğü gibi okunur: widget zaman pencereleri, takvim filtreleri ve latest modu tablolar için geçerlidir ve bir dönüşüm için yok sayılır. Bundan üç kural çıkar. Zaman aralığını sorgunun içinde sınırlayın (WHERE tsp > now() - interval '7 days'), bir zaman serisini en yeniden en eskiye sıralayın (ORDER BY <time column> DESC) ki bir satır sınırı en yeni satırları korusun ve bir panonun çizmesi veya filtrelemesi gereken her sütunu seçin — bir dönüşümün örtük zaman damgası veya cihaz sütunları yoktur. Tek bir okuma en fazla 3000 satır döndürür; bu nedenle toplulaştırmayı sorguda yapın.

Bir dönüşüm, bir tablo okumasının ifade edemediği şeyler içindir: bir join, bir oran, birkaç tablonun mevcut satırları üzerinde bir toplulaştırma. Varlıkların mevcut durumunu göstermenin veya silinen kayıtları gizlemenin yolu değildir. Bunlar tablonun kendisinin okuma modlarıdır — latest anahtarı ve bir deleted sütunu üzerindeki bir filtre (aşağıya bakın) — ve canlı çalışırlar: tabloya bağlı bir widget her yeni satırı bir saniye içinde izler. Bir dönüşüm panoya yalnızca zamanlamasına göre ulaşır (ya da uygulamanın kodu onu kendi yazmalarından sonra tazelediğinde — bir panonun kaydetmesi bunu asla tetiklemez); bu nedenle varlık başına en yeni satırı seçen veya silinen satırları ayıklayan bir görünüm aynı sonucu geç gösterir. Bir dönüşümün bir varlık tablosunun mevcut durumuna gerçekten ihtiyacı olduğunda, örneğin onu başka bir tabloyla birleştirmek için, bunu kendi SQL’inde DISTINCT ON ile seçin ve deleted denetimini, Kayıtları Yumuşak Silme altında gösterilen sırayla orada uygulayın.

Bir dönüşüm elde etmenin tek yolu onu uygulamayla birlikte göndermek değildir: Veri Erişimi yetkisine sahip bir proje üyesi aynı türden bir dönüşümü, hiçbir uygulama olmadan projenin veri görünümünden kaydedebilir; AI asistanı da bunu yapabilir. Bkz. Özel Dönüşümler.

Kalıcılaştırılmış Bir Dönüşüm Ne Zaman Tazelenir

Zamanlanmış bir çalıştırma, kalıcılaştırılmış bir dönüşümü yalnızca okuduğu tablolardan birine son tazelemesinden bu yana yazılmışsa tazeler; bundan bağımsız olarak da en az 10 dakikada bir tazeler. Okuyacak yeni bir şeyi olmayan bir çalıştırma, saklanan sonucu olduğu gibi bırakır: saatte bir satır alan bir tablo üzerinde her dakika çalışacak şekilde zamanlanmış bir dönüşüm, o satırdan sonra, bunun dışında da 10 dakikada bir tazelenir.

Kalıcılaştırılmış bir dönüşüm, sonucu bir yazma olmadan değişebiliyorsa her çalıştırmada tazelenir:

  • SQL’i geçerli zamanı veya rastgeleliği kullanıyorsa, örneğin now(), CURRENT_DATE veya random();
  • aynı girdi için farklı bir sonuç döndürebilen bir fonksiyon çağırıyorsa: volatile (değişken) bir fonksiyon ya da PostgreSQL’de yerleşik olmayan stable (kararlı) bir fonksiyon;
  • uygulama tabloları ve kalıcılaştırılmış dönüşümler dışında bir şey okuyorsa, örneğin kalıcılaştırılmamış bir dönüşüm, aşağı örneklenmiş bir kopya ya da platformun kendi tablolarından biri.

Aynı anda çok sayıda dönüşümün çalışma zamanı geldiğinde platform her seferinde birkaçını tazeler, diğerleri sıralarını bekler; bu nedenle bir tazeleme, planlanandan daha geç bitebilir. Aynı dönüşümün önceki tazelemesi hâlâ çalışırken veya beklerken zamanı gelen bir çalıştırma atlanır.

Talep Üzerine Tazeleme

Uygulamanın kendi kodu, zamanlamasını beklemeden bir dönüşümün çalıştırmasını yapabilir: SDK’nın refresh_transform / refreshTransform / RefreshTransform metodu kalıcılaştırılmış sonucu tazeler (sade bir görünüm yalnızca okunur) ve güncel sonucu dönüşüme bağlı panolara gönderir; böylece bir pano, uygulamanın az önce yazdığı bir yığını hemen gösterir. Zamanlanmış bir çalıştırma için geçerli olan kurallar aynen geçerlidir: dönüşümün okuduğu tablolardan hiçbirine son tazelemeden bu yana yazılmamışsa tazeleme atlanır (ve atlandığı bildirilir), aynı dönüşümün bir tazelemesi çalışırken gelen bir çağrı onun arkasında sıraya alınmış olan tazelemeyi bekler ve dönüşüm başına saniyede en fazla bir tazeleme başlar. SDK’nın tablo yazmaları geri dönmeden önce commit edilir; bu nedenle bir yazmanın ardından gelen bir tazeleme o yazmayı asla kaçırmaz. Bir uygulamanın dönüşümlerini yalnızca kendi kapsayıcıları tazeleyebilir; bir pano satırları alır ve başka bir uygulamanın verilerini tüketen bir uygulama onun dönüşümlerini okur ama tazeleyemez. Projenin veri görünümünden kaydedilen dönüşümler hiçbir uygulamaya ait değildir ve yalnızca zamanlamalarına göre çalışır. Bkz. refreshTransform / refresh_transform.

Bir Varlığın En Son Durumunu Takip Etme

Gerçek dünya varlıklarının mevcut durumunu temsil eden tablolar için — makineler, varlıklar, üretim emirleri — IronFlock en son durum takibi adı verilen bir deseni destekler.

Bir şey değiştiğinde satırın üzerine yazmak yerine, her zaman yeni bir satır eklersiniz. Benzersiz bir varlığı hangi sütunların tanımladığını siz bildirirsiniz; IronFlock da tablo her okunduğunda varlık başına en son satırı türetir. Bu, her değişikliğin tam geçmişini sağlarken yalnızca mevcut durumu sorgulamayı da kolaylaştırır.

maintainLatestFlagFor ile bir tabloda etkinleştirin:

- tablename: machineform maintainLatestFlagFor: ['machinename'] columns: - id: tsp dataType: timestamp - id: machinename dataType: string - id: machinetype dataType: string - id: active dataType: boolean - id: description dataType: string

maintainLatestFlagFor, birlikte benzersiz bir varlığı tanımlayan sütunların listesini alır. Satırın kendisine hiçbir şey yazılmaz: IronFlock tabloyu bu varlık anahtarına ve zaman damgasına göre indeksler ve sorgu anında varlık başına en yeni satırı seçer. Bu nedenle geç ya da sırasız gelen bir satır, geride asla eskimiş bir işaret bırakamaz.

Bir varlık tablosu, varlık ve zaman damgası başına tek bir satır tutar. Saklanan bir satırın hem varlık anahtarını hem de tsp değerini tekrarlayan bir satır reddedilir; iki satırın bunu yaptığı bir yığın da reddedilir: SDK’nın yazması URI_ENTITY_KEY_CONFLICT hatasıyla başarısız olur ve uygulamanın error-logs tablosu reddi kaydeder. Bir varlığın her sürümüne kendi tsp değerini verin. Varlık anahtarı sütunu boş (NULL) olan bir satır hiçbir varlığa ait değildir: asla tekrar olarak reddedilmez ve en son durum okumaları onu dışarıda bırakır.

Bir Varlığı Kısmi Bir Satırla Güncelleme

Bir varlık tablosuna eklenen satır, o varlığın yeni bir sürümüdür — ve eksiksiz olmak zorunda değildir. Satırın sağlamadığı sütunlar, varlığın önceki en son satırından devralınır; dolayısıyla tek bir alanı güncellemek, yalnızca varlık anahtarını, bir zaman damgasını ve o alanı yayımlamak anlamına gelir:

Yeni satırın sütunuSaklanan sürümün tuttuğu
sağlanmışsa (0, false ve "" sağlanmış sayılır)sağlanan değer
açıkça null iseNULL — sütun temizlenir
yoksaönceki en son satırdaki değer

Bir sütunu boşaltmak için onu null olarak gönderin (Python’da None, Go’da nil). Sütunu dışarıda bırakmak önceki değeri korur. Bir alanı istemeden dışarıda bırakan koda dikkat edin: örneğin değeri undefined olan bir JavaScript özelliği veri yükünden düşer. SDK başvurusu bu durumları dile göre listeler.

Bilinmeye değer iki ayrıntı vardır:

  • Tüm sütunları sağlayan bir satır, önceki satırı arama adımını tamamen atlar; dolayısıyla eksiksiz satırlar her zaman olduğu kadar ucuz kalır — yüksek frekanslı yollarda eksiksiz satırlar göndermeye devam edin.
  • Devralma zamana saygı gösterir: daha eski bir zaman damgasıyla gelen bir satır (geriye dönük bir doldurma), yalnızca kendi tsp değerine eşit ya da ondan önceki satırlardan devralır, asla daha yeni olanlardan değil.

maintainLatestFlagFor içermeyen tablolar düz ekleme semantiğini korur: satırın sağlamadığı bir sütun NULL olarak saklanır.

Yalnızca mevcut makine durumlarını sorgulamak için:

SELECT DISTINCT ON (machinename) * FROM machineform ORDER BY machinename, tsp DESC

Belirli bir makinenin tam geçmişini görüntülemek için:

SELECT * FROM machineform WHERE machinename = 'Assembly-Line-01' ORDER BY tsp

Bu sorguyu elle yazmanız nadiren gerekir ve onu bir dönüşüm olarak saklamamalısınız. Bu tabloya bağlanan panodaki widget’ların filtre ayarlarında bir latest anahtarı bulunur; böylece kullanıcılar herhangi bir ek çalışma olmadan her zaman güncel değerleri görür. Anahtar canlıdır: widget, tablonun her yeni satırını geldiği anda alır ve varlığın önceki satırını onunla değiştirir; böylece bir değişiklik yazıldıktan sonra bir saniye içinde görünür, tablo ise her sürümü saklar. Hiçbir şey bir zamanlamaya göre yeniden hesaplanmaz — bir dönüşümün ekleyeceği tek şey de bu olurdu. SDK’dan aynı modu, filterAnd içine {"latest": true} ekleyerek isteyebilirsiniz — bkz. getHistory.

latest_flag’ten yükseltme: IronFlock’un önceki sürümleri latest_flag adında fiziksel bir boolean sütunu saklıyordu. Bu sütun artık mevcut değil — mevcut durum bunun yerine SQL’de türetiliyor; bu da satırlar sırasız geldiğinde bile sonucun doğru kalmasını sağlıyor. latest_flag = true ile filtreleyen mevcut panolar ve SDK çağrıları çalışmaya devam eder: IronFlock bunları tanır ve en son durum modunu uygular. Yeni kodlar latest anahtarını veya {"latest": true} filtre girdisini kullanmalıdır.

Varlık Anahtarını Değiştirme

Bir uygulama sürümü yayımlandıktan sonra, tablolarının her birinin varlık anahtarı sabitlenir. Bulut IDE’nin yan panelindeki Veri Yapısını Güncelle ve yeni bir sürümün derlemesi, uygulamanın en yeni sürümünde bulunan bir tablonun varlık anahtarını değiştiren bir data-template.yml dosyasını reddeder:

  • maintainLatestFlagFor listesine bir sütun eklemek, birini kaldırmak, birini başka bir sütunla değiştirmek veya sütunların sırasını değiştirmek;
  • daha önce maintainLatestFlagFor içermeyen bir tabloya onu eklemek ya da onu kaldırmak.

Böyle bir değişiklik, uygulamanın kurulu olduğu her projede tablonun döndürdüğü şeyi sessizce değiştirirdi. Anahtara yeni eklenen bir sütun mevcut her satırda boştur ve en son durum okumaları anahtar sütunu boş olan satırları dışarıda bırakır; dolayısıyla mevcut tüm varlıklar kaybolurdu. Anahtardan kaldırılan bir sütun, satırları aynı zaman damgasını paylaşan varlıkları birleştirebilir; oysa tablo varlık ve zaman damgası başına yalnızca bir satır tutabilir.

Farklı bir varlık anahtarı kullanmak için yeni anahtarla yeni bir tablo oluşturun ve verileri, örneğin uygulamanızın kodundan, bu tabloya taşıyın. Verileri taşımak uygulamanın işidir. Henüz hiçbir sürümde bulunmayan bir tablonun varlık anahtarı, geliştirme sırasında hâlâ değiştirilebilir. Bu kural yürürlüğe girmeden önce yayımlanmış bir uygulama sürümü bir varlık anahtarını hâlâ değiştirebilir: o sürüme güncellenen bir proje veri yapısı güncellemesini reddeder ve öncekini korur.

Varlığı ve Zaman Damgasını Tekrarlayan Satırlar

IronFlock varlık ve zaman damgası başına tek satır kuralını uygulamaya başlamadan önce yazılmış tablolar hâlâ tekrarlar içerebilir; varlık anahtarını değiştirdiğiniz bir geliştirme tablosu da öyle. Veri hizmeti böyle bir tabloyu kurarken, yani başlangıcında veya bir veri yapısı güncellemesinden sonra, tekrarlanan her gruptaki tüm satırları aynı veri arka ucundaki <table>__entitykey_dupes adlı bir tabloya taşır ve her gruptan bir satırı geri koyar. Bundan sonra tablo tekrarları reddeder. Uygulamanın error-logs tablosundaki bir kayıt, kaç satırın taşındığını belirtir.

Yeni tablo, taşınan her satırı olduğu gibi, iki ek sütunla birlikte saklar: taşıma zamanı olan quarantined_at ve geri konan satırı işaretleyen restored. Hangi satırın geri konduğu, en son durum okumalarında zaten olduğu gibi keyfidir. Tabloyu projenin veri görünümündeki sorgu konsolunda databackend_<key>.<table>__entitykey_dupes olarak sorgulayın. Özgün tablo özel ise yeni tablo da özeldir. Satırlar taşınamazsa error-logs kaydı nedenini belirtir ve veri hizmeti bir sonraki başlangıcında yeniden dener.

Kayıtları Yumuşak Silme

IronFlock’un yalnızca ekleme modeli, kayıtların fiziksel olarak hiçbir zaman silinmediği anlamına gelir. Bunun yerine, bir kaydı kaldırılmış olarak işaretlemek için deleted boolean sütununu kullanın. Bu, tam denetim izini korurken silinen kayıtları dashboard’lardan gizler.

Herhangi bir varlık tablosuna deleted sütunu ekleyin:

- id: deleted name: Deleted dataType: boolean

Bir kullanıcı bir kaydı sildiğinde (örneğin panodaki bir form aracılığıyla), uygulamanız o varlık için deleted: true ile yeni bir satır yayımlar. maintainLatestFlagFor ile birleştiğinde, bu yeni satır en son durum olur. Sonraki kısmi satırlar, deleted işaretini diğer her sütun gibi devralır; dolayısıyla deleted sütununa değinmeyen bir güncelleme, varlığı ne yeniden ortaya çıkarır ne de gizler.

Yalnızca aktif (silinmemiş) mevcut kayıtları sorgulamak için:

SELECT * FROM ( SELECT DISTINCT ON (machinename) * FROM machineform ORDER BY machinename, tsp DESC ) latest WHERE deleted IS NULL OR deleted = false

deleted denetimi, makine başına en son satır seçildikten sonra çalışır. Bu sıra önemlidir: silinen satırları önce ayıklamak, önceki silinmemiş satırın mevcut durum olarak yeniden ortaya çıkmasına yol açar.

Pano widget’ları ve SDK aynı sırayı otomatik olarak uygular — latest anahtarını (veya {"latest": true}) bir deleted filtresiyle birleştirdiğinizde tam olarak bu davranışı elde edersiniz. Silinen kayıtlar form gönderilir gönderilmez dashboard’dan kaybolur, ancak geçmiş ve denetim amacıyla veritabanında kalır.

Panoda bir form, bir kaydı deleted sütununu adlandıran Delete-Flag Column ayarı aracılığıyla siler: form silme sırasında true, her kaydetmede ise false yazar; böylece silinmiş bir kaydı kaydetmek onu geri getirir (bkz. Veri Silme). Kayıtları listeleyen widget’lar tablonun kendisini filtreler. Listeyi temizlemek için hiçbir görünüm veya dönüşüm gerekmez; böyle bir şey bir silmeyi ancak bir sonraki zamanlanmış çalıştırmasında gösterirdi.

Verileri Diğer Uygulamalarla Paylaşma

Data backend’iniz yalnızca sizin uygulamanıza aittir: projede kurulu başka hiçbir uygulama tablolarınızı göremez. data-template.yml içindeki iki isteğe bağlı anahtar bunu değiştirir.

Başka bir uygulamanın verilerini okumak için, okumak istediğiniz uygulamaları üst düzey bir consumes: bölümünde listeleyin — data: bölümünün içinde değil, yanında:

consumes: - app: machine-monitor reason: "Monitörün makine durumu ve sayaç akışlarından OEE hesaplar" data: tables: - tablename: oee_results columns: # ... her zamanki gibi uygulamanızın kendi tabloları

app, veriyi sağlayan uygulamanın teknik adıdır; projedeki tüm uygulamalar için "*" (tırnak işaretleri zorunludur) kullanılır. reason, onay penceresinde kullanıcıya gösterilir — bildirimin kendisi, kullanıcı onaylamadıkça hiçbir erişim vermez.

Belirli tabloları paylaşım dışında tutmak için bunları private: true ile işaretleyin. Tanımladığınız her şey varsayılan olarak paylaşılabilirdir; özel bir tablo veya dönüşüm, diğer uygulamaların gördüğü katalogda hiç görünmez.

data: tables: - tablename: measurements # paylaşılır (varsayılan) columns: [ ... ] - tablename: calibration_state # dahili — diğer uygulamalara asla görünmez private: true columns: [ ... ]

Erişim salt okunurdur, kullanıcı tarafından proje bazında verilir ve istendiği zaman geri alınabilir. Modelin tamamı ve sağlayıcı uygulamanın geçmiş ile canlı akışlarını okuyan SDK çağrıları için bkz. Diğer Uygulamaların Verilerini Kullanma.

Ayrıcalıklı Erişim

Bir uygulamanın container’ları cihazdan yalıtılmış olarak, Docker’ın varsayılan haklarıyla çalışır. Bazı uygulamalar daha fazlasına ihtiyaç duyar: bir seri port veya USB adaptörü, GPIO, bir CAN veya Bluetooth arayüzü, host ağı. Buna ayrıcalıklı erişim denir. Ayrıcalıklı erişime sahip bir uygulama, diğer uygulamalar ve verileri dahil olmak üzere cihazın tamamını kontrol edebilir; bu yüzden uygulamanızın bunu talep etmesi gerekir ve verilip verilmeyeceğine kullanıcı karar verir.

Talep etmek için, üst düzeye reason içeren bir privileged: bölümü ekleyin — data: bölümünün içine değil, yanına:

privileged: reason: "PLC'yi /dev/ttyUSB0 seri portu üzerinden okur" data: tables: # ... her zamanki gibi uygulamanızın kendi tabloları

reason zorunludur. Onay penceresinde kullanıcıya gösterilir; bu yüzden onu, uygulamanıza güvenip güvenmeyeceğine karar veren biri için yazın.

Tablosu olmayan bir uygulama privileged yanına data: {} yazar: data: anahtarı olmayan bir data-template.yml yayımlanamaz.

Kullanıcının neye izin verdiği, uygulamanın nasıl oluşturulduğuna bağlıdır:

  • Tek imajlı bir uygulama (yalnızca bir Dockerfile) kullanıcı izin verdiğinde ayrıcalıklı modda çalışır: tüm Linux yetenekleri (capabilities), cihazın /dev dizini ve host’un D-Bus’ı ile. Bildirim olmadan host’un cihazları, ek yetenekler ve host’un D-Bus’ı olmadan çalışır; sürüm yine de yayımlanır ve derleme günlüğü bu konuda uyarır.
  • Bir Docker Compose uygulaması tam olarak docker-compose.yml dosyasının istediği ayarları alır ve onay penceresi bunları listeler. Compose dosyası aşağıdaki ayarlardan herhangi birini kullanıyorsa uygulama privileged bildirmelidir; aksi halde sürümün yayımlanması, servisi ve ayarı belirten bir hatayla başarısız olur. Compose dosyası bunların hiçbirini kullanmıyorken privileged bildirmek de başarısız olur.

Şu compose ayarları ayrıcalıklı sayılır:

AyarAyrıcalıklı sayıldığı durum
privilegedfalse dışındaki her değer
cap_add, devices, device_cgroup_rulesbir girdisi olduğunda
security_optno-new-privileges dışında bir girdisi olduğunda
network_mode, pid, ipc, uts, userns_mode, cgrouphost veya container:… olarak ayarlandığında
cgroup_parentbir değer atandığında
bir servisin volumes ayarıbir host yolunu (/…, ~/…, C:\…), uygulama klasörü dışındaki bir yolu (../…) veya bir named pipe’ı bağladığında. Salt okunur /etc/localtime ve /etc/timezone sorun değildir.
volumes_fromcontainer:… belirttiğinde
üst düzey volumesbir volume’ün driver_opts, external veya sabit bir name değeri olduğunda
üst düzey networksbir ağ bridge dışında bir driver (örneğin macvlan, ipvlan veya host) ya da driver_opts belirlediğinde, external olduğunda veya sabit bir name değeri olduğunda
üst düzey secrets, configsbir girdi uygulama klasörü dışındaki bir file dosyasını okuduğunda

Adlandırılmış volume’ler, varsayılan bridge sürücüsünü kullanan ağlar, uygulama klasörü içindeki bind mount’lar (./config:/config), yayımlanan portlar ve GPU rezervasyonları (gpus, deploy.resources.reservations.devices) ayrıcalıklı değildir.

Bu ayarlardan birinde ${VAR} yer tutucusu kullanmak serbesttir ve ayrıcalıklı sayılır; yani bunun için de bildirim gerekir. Bir uygulama parametresi kullanıcıların seri portu seçmesini böyle sağlayabilir:

services: plc: build: . devices: - "${SERIAL_PORT}:/dev/ttyS0"

include veya file içeren extends kullanan bir compose dosyası, bildirim olsun ya da olmasın yayımlanamaz: bir sürüm yalnızca docker-compose.yml dosyasını taşır. Diğer dosyaları bu dosyada birleştirin.

Uygulamanın ihtiyacından fazlasını talep etmeyin. Uygulama tek bir seri porta ihtiyaç duyuyorsa, tek imaj veya privileged: true yerine tek bir servis ve devices: [/dev/ttyUSB0] içeren bir compose dosyası yazın. Kullanıcı uygulamanın tam olarak ne aldığını görür ve uygulama bundan fazlasını yapamaz.

Onay ve Geri Alma

  • Kurulumda kullanıcı reason metninizi ve compose uygulamaları için ayarların listesini görür, ayrıcalıklı erişimi açar veya kapatır. Reddetmek kurulumu asla engellemez.
  • Bir güncellemede, yeni sürüm ayrıcalıklı erişim talep ediyorsa ve proje buna izin vermemişse güncelleme penceresi sorar. Reddedilse bile uygulama güncellenir; yeni sürüm bu durumda ayrıcalıklı erişim olmadan çalışır.
  • Sonrasında ayrıcalıklı erişim, projenin uygulama ayarlarında bir anahtardır; kullanıcılar onu orada istedikleri zaman geri alabilir veya verebilir. Çalışan cihazlar uygulamayı yeni ayarla yeniden başlatır.

Cloud IDE’den başlatılan geliştirme modu bildirime uyar ve bir anahtarı yoktur: .ironflock/data-template.yml privileged bildiriyorsa geliştirme derlemesi ayrıcalıklı çalışır, bildirmiyorsa ayrıcalıklı erişim olmadan çalışır. Compose dosyası bildirim olmadan ayrıcalıklı ayarlar kullanıyorsa geliştirme derlemesi, yayımlamadaki hatanın aynısıyla başarısız olur.

İzin Verilmediğinde

Uygulama yine de başlar. Tek imajlı bir uygulama Docker’ın varsayılanlarıyla çalışır: /dev yok, ek yetenek yok, host’un D-Bus’ı yok. Bir compose uygulamasında cihaz ajanı, uygulamayı başlatmadan önce ayrıcalıklı ayarları compose dosyasından kaldırır ve hangi servisten hangi ayarları kaldırdığını uygulamanın loguna yazar. Kodunuzun, erişemediği şeyleri (örneğin açamadığı bir seri portu) çökmek yerine bildirmesini sağlayın.

Önceki Sürümler

Uygulamaların ayrıcalıklı erişimi bildirmesi zorunlu olmadan önce yayımlanan sürümler, bu erişimi talep ediyormuş gibi sayılır ve mevcut kurulumlar bu erişimi korur; böylece bu uygulamalar eskisi gibi çalışır. Kullanıcılar, diğer tüm uygulamalarda olduğu gibi, projenin uygulama ayarlarından bu erişimi geri alabilir. Bir sonraki sürümünüzden itibaren, uygulamanın ihtiyacı varsa privileged bildirin.

Last updated on