15 Haziran 2021 Salı

Server Sent Events Nedir

Giriş
Açıklaması şöyle. Server Sent Events (SSE) Real Time Notification (Gerçek Zamanlı Bildirimler) içindir. SSE tüm tarayıcılar tarafından desteklenir.
Server Sent Events (SSEs) is a server push technology enabling a client to receive automatic updates from a server via HTTP connection.
Mesaj Formatı Nasıldır?
Açıklaması şöyle
The events are just a stream of UTF-8 encoded text data in a format defined by the Specification. The important aspect here is that the format defines the fields that the SSE message should have, but it does not mandate a specific type for the payload, leaving the freedom of choice to the users.
Bir başka açıklama şöyle
How does SSE work ?
A client subscribes to a stream from a server and the server will send messages (“event-stream”) to the client until the server or the client closes the stream. It is up to the server to decide when and what to send the client.

The event-stream is a simple stream of text data which must be encoded using UTF-8. Messages in the event-stream are separated by a pair of newline characters (“\n”).

The following field names are defined in the specification:

Event: The event’s type. It will allow you to use the same stream for different content. A client can decide to “listen” only to one type of event or to interpret differently each event type.

Data: The data field for the message. You can put consecutive “data” lines.

ID: ID for each event-stream. Useful to track lost messages.

Retry: The time to use before the browser attempts a new connection after all connections are lost (in milliseconds).
Id ve Event seçenekleri isteğe bağlıdır. Her satır "\n" karakteri ile biter. Mesaj sonunda da "\n" karakteri vardır.
Örnek 
Eğer metin olarak bakarsa şöyledir
"event: " sometext\n
"data: " sometext\n
\n
Örnek
{
 "id": "message id <optional>",
 "event": "event type <optional>",
 "data": "event data –plain text, JSON, XML… <mandatory>"
}
SSE İçin Context-Type Nasıldır?
Açıklaması şöyle
For the SSE to work, the server needs to tell the client that the response’s content-type is text/eventstream
Örnek
İstemci şunu gönderir
GET /sse HTTP/1.1 
Host: server.com
Accept: text/event-stream
Sunu şöyle cevaplar
HTTP/1.1 200 OK
Connection: keep-alive Content-Type: text/event-stream Transfer-Encoding: chunked retry: 1000 data: A text message data: {"message": "a JSON message"} event: text data: A message of type 'text' id: 1 event: text data: A message of type 'text' with a unique identifier :ping
Server Sent Events ve WebSocket Farkı Nedir?
Açıklaması şöyle
You can send unidirectional events using the SseEmitter class in Spring. There is already a popular solution available for sending bi-directional events using Websockets. Using WebSockets both server and clients can communicate with each other using bi-directional connections between client and server. SSE is only used for sending uni-directional events from the server to clients using the HTTP protocol.
Açıklaması şöyle
When it comes to SSE, it is often compared to Websockets due to usage similarities between both of the technologies.

- Both are capable of pushing data to the client,
- Websockets are bidirectional – SSE unidirectional,
- In practice, everything that can be done with SSE, and can also be achieved with Websockets,
- SSE can be easier,
- SSE is transported over a simple HTTP connection,
- Websockets require full duplex-connection and servers to handle the protocol,
- Some enterprise firewalls with packet inspection have trouble dealing with Websockets – for SSE that’s not the case,
- SSE has a variety of features that Websockets lack by design, e.g., automatic reconnection, event ids,
- Only Websockets can send both binary and UTF-8 data, SSE is limited to UTF-8, 
- SSE suffers from a limitation to the maximum number of open connections (6 per browser + domain). The issue was marked as Won’t fix in Chrome and Firefox.
Spring İle SSE
Server Sent Events Nedir yazısına taşıdım

Tarayıcı Tarafında 
EventSource kullanılır

11 Haziran 2021 Cuma

Yazılım Dünyasında Sistem Mühendisi

Giriş
Not : Bu yazı yarım kaldı. Düşüncelerimi tam olarak düzenleyemedim :)

Yazılım dünyasında "Sistem Mühendisi" nedir sorusuna tam olarak cevap verebilmek çok kolay değil.
- Müşteri mi ?
- Tecrübeli bir yazılımcı mı ?
1. Sistem Nedir?
Bir sistemi tarif et dediklerinde insanın aklına şu maddeler geliyor. 
Önce şu soruya cevap vermek gerekir. Sistem ne işi gerçekleştirir, nerede kullanılır/kullanılmaz. Yani mahareti nedir?
2. Daha Sonra Farklı Bakış Açıları İle Tarif Etmek Gerekir

2.1 Veri Merkezli (Data Oriented) Bakış Açısı
- Bilginin nereden nereye akmaktadır. Nasıl işlenmektedir, nerede saklanmaktadır.
2.1 Çalıştırma/İşletme Bakış Açısı
- Yazılımın/Sistemin açılış/kapanış senaryoları nasıldır
- Yazılım kaç bilgisayar/cluster üzerinde çalışmaktadır. 
2.2 Mimarisel Bakış Açısı
- Sistemin en temel Functional isterleri nelerdir.

- Sistemin Non-Functional (Non-Functional Requirements) isterleri nelerdir. NFR deyince Yazılım Kalite Etmenleri - Software Quality Attributes maddeleri de akla geliyor.
2.3 Kullanıcı Deneyimi - User Experience (UX) Bakış Açısı
Kullanıcı Deneyimi'nin amacı sadece bir işlevi yerine getirmek değil. Onu onu en kolay/verimli şekilde yerine getirmek.
3. Tüm Bunlara Nasıl Cevap Veririm
Tüm bunlara cevap vermenin çeşitli yolları var. Bazıları şöyle
- Her bakış açısıyla bol bol yazıp çizmek. Her kararı her düşünceyi kayıt altına almak. Bu belgeler daha sonra yazılımcılara ve testçilere kaynak olacaktır.
- Yazıp çizecek kadar vakit yoksa, sürekli iletişimde bulunmak. Yazılım ve test ekibiyle dirsek temasını koruyarak, sürekli dürtmek
4. Yazıp Çizmenin Adabı
Her işte olduğu gibi yazıp çizmenin de bir adabı var.

Örnek
Bir projede şöyle bir durumla karşılaştık. Sistem Mühendisi sadece "Veri Merkezli" bakış açısıyla düşünüyordu. Yazılımcılara sağlanan tek kaynak, şu veri bu cihazdan okunur ve şuraya gönderilir şeklindeydi. Bu bilgiyi de Excel'de saklamayı tercih ediyordu ve Excel'ler V1, V2, V3 şeklinde versiyonlarla gidiyordu. İşin püf noktası detaylarda olduğu için yazılımcılar sürekli 
- Bu verinin hangi alanını/sütununu diğer sistem göndereceğiz ?
- Birimi ne olacak?
- Gönderme/alma sıklığı ne olacak?
- Tüm veriyi mi işleyeceğiz, yoksa bazı verileri süzecek miyiz? 
gibi sorular soruyorlardı. Bu soruları artırmak mümkün.

Demek ki yazıp çizmeye başlayınca, ortaya çıkan sorulara göre de yazılanları değiştirmek gerekiyor. Excel bu işe uygun mu tartışılır. Hesaplama için kullanılan bir uygulamanın not almak için hele de metin/şekil/görsel gerektiren bir notlar için kullanılması bence uygun değil.





 


10 Haziran 2021 Perşembe

DDS Lifespan QoS - Yaşam Süresi Yani Expiration Time

Giriş
Lifespan QoS verinin yaşam süresini belirtiyor. Veri güncellendiği müddetçe yaşam süresi yenileniyor, ancak güncellenmezse ve belirtilen yaşam süresi biterse DDS önbelleğinden siliniyor. Açıklaması şöyle
The purpose of this QoS is to avoid delivering "stale" data to the application.

Each data sample written by the DataWriter has an associated 'expiration time' beyond which the data should not be delivered to any application. Once the sample expires, the data will be removed from the DataReader caches as well as from the transient and persistent information caches.
...
This QoS relies on the sender and receiving applications having their clocks sufficiently synchronized. If this is not the case and the Service can detect it, the </blockquote>is allowed to use the reception timestamp instead of the source timestamp in its computation of the 'expiration time'

DataWriter Açısından
Gönderilmek üzere DataWriter belleğinde bekleyen yaşam süresi dolmuş veriler, DDS tarafından silinirler. Böylece eski veri dağıtılmayarak kaynak kullanımına katkıda bulunulur.

DataReader Açısından
DataReader tarafından henüz okunmamış ancak yaşam süresi dolmuş veriler, DDS tarafından silinirler. 

Örnek
Örneğin taktik veri linklerinde bir iz belli bir süre boyunca güncellenmezse o iz sistemden düşürülür. DDS ile iz kuyruğuna Lifespan QoS parametresi atanırsa, izin temizlenme işi DDS tarafından otomatik olarak yapılır.

National Maritime Electronics Association - NMEA Weather Instrument (Meteorolojik) Mesajları

Giriş
Hava durumuyla ilgili bilgileri verir. Genellikle saniyede 1 tane gelirler. Talker ID olarak "WI" Wind Instruments anlamına gelir. 

- Bu cihazı gerçek kuzeyi bulsun diye, Gyro'dan veya Magnetic Compass'tan gelen HDT - Heading True mesajı ile beslemek gerekir.
- Ayrıca geminin hızını bilmesi için Navigation Radar'dan gelen OSD - Own Ship Data ile beslemek gerekir.

1. MWV - Wind Speed And Angle - Geminin Kendisine Göre, Bağıl (Relative) Rüzgar Bilgisi
Manyetik veya gerçek kuzeye göre değil geminin kendi gittiği yöne göre rüzgarı raporlar. Rüzgar geminin hızına göre (relative) veya gemi duruyormuş (theoretical) şekilde raporlanabilir. 

Bu bilgi gemideki mekanik cihazlar için önemlidir. Örneğin silahlar bağış rüzgardan etkilendikleri için bu bilgiye ihtiyaç duyarlar. 

Mesaj alanları şöyle
Wind Angle, 0 to 359 degrees
Reference, R = Relative, T = True
Wind Speed
Wind Speed Units, K/M/
Status, A = Data Valid, V = Invalid
2. MWD - Wind Direction & Speed - Mutlak (Absolute) Rüzgar Bilgisi
Manyetik veya gerçek kuzeye rüzgar raporlanır.

Mesaj alanları şöyle
Wind Direction, 0 to 359 degrees True
Wind Direction, 0 to 359 degrees Magnetic
Wind Speed, Knots
Wind Speed, meters/second
3. MTA - Air Temperature - Kullanmayın
Bu mesajın yeni tasarımlarda kullanılmaması öneriliyor. XDR kullanılmalı.

Hava sıcaklığı. Mesaj alanları şöyle
Temperature, degrees C
4. MHU - Humidity - Kullanmayın
Bu mesajın yeni tasarımlarda kullanılmaması öneriliyor. XDR kullanılmalı.

Nem. Mesaj alanları şöyle
Relative humidity, percent
Absolute humidity, percent
Dew point, degrees C
5. MMB - Barometer - Kullanmayın
Bu mesajın yeni tasarımlarda kullanılmaması öneriliyor. XDR kullanılmalı.

Barometre. Mesaj alanları şöyle
Barometric pressure, inches of mercury
Barometric pressure, bars

8 Haziran 2021 Salı

gRPC Client

Giriş
- Önce bir tane io.grpc.ManagedChannel yaratılır. Açıklaması şöyle
ManagedChannelBuilder is an abstract class and there are concrete implementations like NettyChannelBuilder and OkHttpChannelBuilder. When you use an API like ManagedChannelBuilder.forTarget() or Grpc.newChannelBuilder() gRPC finds an appropriate concrete implementation based on your platform and returns it (normally OkHttp on Android; Netty otherwise).
Daha sonra bir sub yaratılır. Blocking ve Non-blocking olarak iki tane stub çeşidi var. Açıklaması şöyle
gRPC supports two types of client stubs:
1. blocking/synchronous stub: in this stub, the RPC call waits for the server to respond.
2. non-blocking/asynchronous stub: client makes non-blocking calls to the server, where the response is returned asynchronously.
Blocking Stub
- ManagedChannel kullanılarak MyService.newBlockingStub(channel) çağrısı ile bir stub yaratılır. Stub servis çağrılarını içerir. Bu servis çağrılarını kullanarak gRPC kullanılır

- İşimiz bitince channel().awaitTermination() çağrısıyla kanal kapatılır

Non-blocking Stub With Callback
ManagedChannel kullanılarak MyService.newStub(channel) çağrısı ile bir stub yaratılır. Stub'a StreamObserver arayüzünü gerçekleştiren bir tane callback takılır. Callback gRPC'nin kendi threadleri üzerinde gerçekleşir. Açıklaması şöyle
For the callback, gRPC uses a cached thread pool that creates new threads as needed but will reuse previously constructed threads when they are available. 
Eğer kendi threadlerimizi kullanmak istersek bunu ManagedChannel seviyesinde yapmak gerekir. Şöyle yaparız
var executorService = Executors.newFixedThreadPool(10); 
var managedChannel = ManagedChannelBuilder.forAddress(host,port).executor(executorService)
  .usePlaintext() .build();
Non-blocking Stub With Future
Şöyle yaparız
// Create a new future stub 
var productServiceFutureStub = ProductServiceGrpc.newFutureStub(managedChannel);

var productRequest = GetProductRequest.newBuilder().setProductId("apple-123").build(); 
ListenableFuture<GetProductResponse> listenableFuture = productServiceFutureStub
  .getProduct(productRequest); 
Futures.addCallback(listenableFuture, new ProductCallback(), fixedThreadPool);

//or if you want Runnable
listenableFuture.addListener(this::notifyListener, fixedThreadPool);
Örnek - Blocking Stub
Şöyle yaparız
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.StatusRuntimeException;

import io.octutorials.ocgrpc.Defs.Payload;
import io.octutorials.ocgrpc.FetchGrpc;

import com.google.protobuf.ByteString;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.concurrent.TimeUnit;

public class TutorialClient {
  private final ManagedChannel channel;
  private final FetchGrpc.FetchBlockingStub stub;

  public TutorialClient(String serverHost, int serverPort) {
    this.channel = ManagedChannelBuilder.forAddress(serverHost, serverPort)
      .usePlaintext(true)
      .build();
    this.stub = FetchGrpc.newBlockingStub(this.channel);
  }

  public void shutdown() throws InterruptedException {
    this.channel.shutdown().awaitTermination(4, TimeUnit.SECONDS);
  }

  public String capitalize(String data) throws Exception {
    ByteString bs = ByteString.copyFrom(data.getBytes("UTF8"));
    Payload in = Payload.newBuilder().setData(bs).build();
    Payload out = this.stub.capitalize(in);
    return out.getData().toString("UTF8");
  }
}
Örnek - Blocking Stub
Şöyle yaparız
var productServiceBlockingStub = ProductServiceGrpc.newBlockingStub(managedChannel);
var productRequest = GetProductRequest.newBuilder().setProductId("apple-123").build(); var productResponse = productServiceBlockingStub.getProduct(productRequest);
Örnek - Non-blocking Stub
Şöyle yaparız
var productServiceAsyncStub = ProductServiceGrpc.newStub(managedChannel);
var productRequest = GetProductRequest.newBuilder().setProductId("apple-123").build(); productServiceAsyncStub.getProduct(productRequest, new ProductCallback()); class ProductCallback implements StreamObserver<GetProductResponse> { @Override public void onNext(GetProductResponse value) { log.info("Received product, {}", value); } @Override public void onError(Throwable cause) { log.error("Error occurred, cause {}", cause.getMessage()); } @Override public void onCompleted() { log.info("Completed"); } }
b

gRPC Service

Kendi Servisimiz
proto dosyasındaki Servisin ismi Foo olsun. Kod üretildikten sonra kendi servisimiz şu şekilde kalıtır. FooGrpc üretilen koda ait bir "naming convention"
FooImpl extends FooGrpc.FooImplBase {...}
Eğer cevap döneceksek şöyle yaparız
responseObserver.onNext();
responseObserver.onCompleted();
Eğer hata varsa şöyle yaparız
responseObserver.onError()
Veri Tipleri
Protobuf dosyasında bytes olarak tanımlı bir alanı String'e çevirmek için com.google.protobuf.ByteString kullanılır

Unary Service
gRPC Unary Service yazısına taşıdım

Örnek - Bi-Directional
Şöyle yaparız
@Override
public StreamObserver<UserDetailsRequest> generateRandomUserStream(
StreamObserver<UserDetailsResponse> responseObserver) {
  return new StreamObserver<UserDetailsRequest>() {
    @Override
    public void onNext(UserDetailsRequest input) {
      UserDetailsResponse output = ...;
      responseObserver.onNext(output);
    }
    @Override
    public void onError(Throwable throwable) {
      ...
    }
    @Override
    public void onCompleted() {
      responseObserver.onCompleted();
    }
  };
}

gRPC Maven Dependency

Giriş
- grpc-protobuf ve grpc-stub bağımlılığı kesin gerekiyor. 
- grpc-netty-shaded veya grpc-netty arasındaki farkı bilmiyorum
- Java 9 ve üstü için annotations-api gerekiyor.

Stub Bileşeni
Açıklaması şöyle. Kendi kodumuzu yazarken kullandığımız StreamObserver gibi sınıflar bu bileşenden geliyor.
The Stub layer is what is exposed to most developers and provides type-safe bindings to whatever datamodel/IDL/interface you are adapting. gRPC comes with a plugin to the protocol-buffers compiler that generates Stub interfaces out of .proto files, but bindings to other datamodel/IDL are easy and encouraged.
Transport Bileşeni
Açıklaması şöyle
gRPC comes with three Transport implementations:

- The Netty-based transport is the main transport implementation based on Netty. It is for both the client and the server.
- The OkHttp-based transport is a lightweight transport based on OkHttp. It is mainly for use on Android and is for client only.
- The in-process transport is for when a server is in the same process as the client. It is useful for testing, while also being safe for production use.
Örnek - java 9
Şu satırı dahil ederiz
<dependency>
<groupId>io.grpc</groupId> <artifactId>grpc-stub</artifactId> <version>${grpc.version}</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-protobuf</artifactId> <version>${grpc.version}</version> </dependency> <dependency> <groupId>jakarta.annotation</groupId> <artifactId>jakarta.annotation-api</artifactId> <version>1.3.5</version> <optional>true</optional> </dependency>
Örnek
Şu satırı dahil ederiz. Burada önemli olan şey grpc-netty. grpc-netty sunucu başlatmak için gerekir.
<dependency>
  <groupId>com.google.protobuf</groupId>
  <artifactId>protobuf-java</artifactId>
  <version>3.6.1</version>
</dependency>
<dependency>
  <groupId>io.grpc</groupId>
  <artifactId>grpc-netty</artifactId>
  <version>1.30.0</version>
</dependency>
<dependency>
  <groupId>io.grpc</groupId>
  <artifactId>grpc-protobuf</artifactId>
  <version>1.30.0</version>
</dependency>
<dependency>
  <groupId>io.grpc</groupId>
  <artifactId>grpc-stub</artifactId>
  <version>1.30.0</version>
</dependency>
Örnek
Şu satırı dahil ederiz
<dependency>
  <groupId>io.grpc</groupId>
  <artifactId>grpc-netty-shaded</artifactId>
  <version>1.30.2</version>
</dependency>
<dependency>
  <groupId>io.grpc</groupId>
  <artifactId>grpc-protobuf</artifactId>
  <version>1.30.2</version>
</dependency>
<dependency>
  <groupId>io.grpc</groupId>
  <artifactId>grpc-stub</artifactId>
  <version>1.30.2</version>
</dependency>
<dependency>
<!-- necessary for Java 9+ --> <groupId>org.apache.tomcat</groupId> <artifactId>annotations-api</artifactId> <version>6.0.53</version> <scope>provided</scope> </dependency>