Forholdet mellom Webservice og databaser
Problemer i koblingen Webservice - database
Bruk av RT og Jira - saksgang mellom utvikling og forvaltning
Forholdet mellom Webservice og databaser
Webservicene for FSWS baserer seg både på direkte SQL og prosedyrekall. En god del spørringer er direkte SQL der man går direkte på tabellene i FS og sammenstiller dataene på serversiden før de returneres. En del andre spørringer kaller opp PL/SQL-prosedyrer som sammenstiller dataene i databasen før de sendes gjennom webservicen. Vi har satt som regel at alle kall på å skrive til databasen går via prosedyrekall.
Miljøer
Vi opererer med tre miljøer i FSWS:
- Utv: FSUTV + w3utv-jb01.uio.no
- Test: FS Demo + jboss-test.uio.no (w3test0N.uio.no)
- Prod: FS Prod + fsws.usit.no (w3prod0N.uio.no)
Utviklingsmiljøet har vi full kontroll over via SQL*Plus/SQL Developer/Toad og JBoss Management-konsoll.
De to andre miljøene administreres av Drift (www-drift for applikasjon og oracle-drift for database).
Bruk av GIT
Generelt
All koden til FSWS ligger i GIT, under FS-prosjektet. Følgende kode finnes:
- fsws-db: PL/SQL-kode og tabelldefinisjoner for FSWS
- fsws-core: Felles kode for alle webservices
- fsws-rest: Kode for REST-webservice
- fsws-soap: Kode for SOAP-webservice
- fsws-intern: Kode for intern-webservice, en proxy-tjeneste som databasen bruker for å sende data
Vi strever etter å følge GIT-flow mønsteret for utvikling, men det hender ting glipper. Minimumskravet er dette:
- Master-branch skal aldri røres. Her skal det kun ligge releaseversjoner.
- Develop-branch skal være konsistent, stabil og kompilerbar. Koden som ligger i develop må ikke til en hver tid være perfekt og releasebar (selv om det er en fordel!), men det må kunne kompileres slik at ikke kode som ender i develop stopper andres utvikling.
- Kode under utvikling/testing ligger i brancher.
Mer detaljert bruk av Git kommer i eget dokument. Ellers finnes det masser av eksempler på nett.
Bruk av Git-branches
De fleste prosjektene benytter seg av en "develop" branch for å sikre seg at ting ikke sjekkes inn i master. I tillegg så tar man ofte i bruk egne branches for å utvikle. Her er et eksempel på bruk:
Trinn 1: Opprette branch fra Jira
Utdrag fra Git-kommandolinje:
richared@USIT93-59 /c/git/demo (master) $ git pull From ssh://utv.uio.no:7999/fs/demo * [new branch] bugfix/FSWS-1055-sak-for-a-demonstrere-branching -> origin/bugfix/FSWS-1055-sak-for-a-demonstrere-branching Already up-to-date.
Her ser man at ny branch er hentet ned. Nå bytter vi til denne branchen for å jobbe med den:
richared@USIT93-59 /c/git/demo (master) $ git checkout bugfix/FSWS-1055-sak-for-a-demonstrere-branching Branch bugfix/FSWS-1055-sak-for-a-demonstrere-branching set up to track remote branch bugfix/FSWS-1055-sak-for-a-demonstrere-branching from origin. Switched to a new branch 'bugfix/FSWS-1055-sak-for-a-demonstrere-branching'
OBS OBS! Husk at man må sjekke inn på branch før man eventuelt bytter til en annen branch. Se her:
Gjør endringer og sjekk inn... Resten av jobben gjøres i Stash:
Vi lager derfor en Pull request:
FSWS-DB
Struktur på databasekoden
Databasekoden for FSWS er trukket ut av FS-koden for øvrig, og lagt i eget repo fsws-db (under fs). Her er det laget kopier av alle aktuelle underkataloger, slik at strukturen i FS-repoet (db) er bevart (i hvert fall inntil videre). I tillegg er det lagt til noe:
- FS
- PROG (pakker)
- VPD (VPD-policies)
- FSSYS (temp.tabeller)
- REPORT (rapporter)
- scripts (Python-script for generering av release)
Foreløpig deployes koden til FS-skjemaet, men på sikt er det ønskelig med egne skjemaer som gjenspeiler repo-strukturen.
Retningslinjer for klientoppsett
Det er flere måter å kjøre SQL på (SQL*Plus, Toad, SQL Developer) som har forskjellig oppsett. I den grad det er mulig i det enkelte verktøy, anbefales det å kjøre med noen form for warnings, for å sikre best mulig kodekvalitet.
SQL*Plus (lokalt eller på fs-patch01)
Verktøyet opererer med en init-fil login.sql, som må ligge i katalogen man starter fra (hvis man kjører fra flere kataloger, anbefales det å ha én sentral init-fil som de katalogspesifikke filene starter opp).
Datoformat og kompilator-flagg
-- Default er DD-MON-YY i DOS-versjonen av SQL*Plus
alter session set NLS_DATE_FORMAT = 'DD.MM.YYYY'
/
-- PL/SQL-kompilatoren har en rekke warnings, men i praksis gir noen av dem for mange varsler, så disse anbefales disablet:
alter session set PLSQL_WARNINGS = 'ENABLE:ALL', 'DISABLE:7202', 'DISABLE:7204', 'DISABLE:5018'
/
alter session set PLSCOPE_SETTINGS= 'IDENTIFIERS:ALL'
/
Server-output
set termout off
exec dbms_output.enable
set termout on
set serveroutput on size 1000000
-- Fjerner trailing blanks (pga. linesize)
set trimspool on
SQL*Plus prompt
For å unngå å jobbe i feil skjema/database (og i verste fall rote det til i Prod!), er det anbefalt å sette opp SQL*Plus-prompten til å vise skjema/database man til enhver tid er logget inn i (default er "SQL> "). Skjema hentes fra USER_USERS og database fra GLOBAL_NAME, mens et SQL*Plus-triks sørger for at resultatet av en SELECT havner i ønsket SQL*Plus-variabel (SQLPROMPT):
set verify off
set heading off
set feedback off
define new_prompt='***'
column prval new_value new_prompt
select <Uttrykk på USERNAME og GLOBAL_NAME> prval
from
USER_USERS,
GLOBAL_NAME
where
1=1
/
set sqlprompt "new_prompt"
set verify on
set heading on
set feedback on
Toad (lokalt)
<Anbefalte settinger>
SQL Developer (lokalt)
<Anbefalte settinger>
Retningslinjer for programmering (best practices)
Modularisering og ytelse står ofte mot hverandre i databaseprogrammering. Når ytelse er et issue (som det ofte er i integrasjonssammenheng) er det noen ting man må unngå:
1) Generelt: Funksjoner som kalles fra SQL, og i sin tur utfører egen SQL (optimizeren klarer ikke å resonnere)
2) XML-spesifikt: SELECT XMLElement (...) FROM Dual; på detaljnivå (dvs. der denne kalles mange ganger)
Dette betyr at man går glipp av en del modulariseringsmuligheter, og typisk må duplisere funksjonalitet inline i aktuelle SQL. F.eks. gjør 1) at man ikke kan bruke FS-funksjoner som gjør egne spørringer på detaljnivå hvis hovedspørringen behandler store datamengder. Årsaken til at 2) kan være ønskelig, er at SQL/XML (XMLElement osv) kun kan kalles i en spørring: Hvis man ønsker å generere et XML-element for en enkelt forekomst, må man gjøre det i en spørring som returnerer en enkelt rad (noe som typisk gjøres fra Dual).
Det finnes dog en annen mekanisme som gir en viss mulighet for modularisering uten å bruke funksjoner: Subquery factoring. Man kan angi en eller flere navngitte delspørringer foran hovedspørringen, som kan brukes i sistnevnte:
WITH q1 AS (SELECT ...), q2 AS (SELECT ...), ...
SELECT ... q1 ... q2 ... ;
NB! Faktoriserte subspørringer gir opphav til "temporary tables", noe som kan gi dårlig ytelse hvis datasettet er for stort.
Problemer i koblingen Webservice - database
Når webservicene kaller prosedyrer i databasen så skjer dette ved at man i webservice-koden definerer navnet på metoden man vil kalle og med hvor mange parametere. Deretter gjøres det JDBC-kall mot databasen med riktig metodesignatur. Dette fører til et vesentlig problem: Fordi databasekoden og webservice-koden ikke er direkte linket, vil ikke endringer i grensesnittene i databasen automatisk gi utslag i webservicen - før det er for seint (dvs. når koden brekker). Altså: Dersom man enten endrer på kallet i webservicen eller grensesnittene i databasen uten at de to er synkronisert, vil webservice-kallene feile. I tillegg har man nok et problem: FS kjører på flere baser - derfor rulles ikke databasekoden ut samtidig til alle baser. Webservicen, derimot, kjører mot alle baser samtidig og kan derfor kalle både nye og gamle grensesnitt samtidig. Altså: Når man endrer et grensesnitt i databasen, så vil webservicen måtte håndtere både nytt kall-grensesnitt og gammelt kall-grensesnitt samtidig.
For å bøte på disse problemene har vi definert følgende operasjonsmodus når man vil endre på et kallgrensesnitt i basen, f.eks. ved å legge på et nytt felt:
- 1: Opprett det nye grensesnittet i PK_FSWS. NB! Ikke slett det gamle grensesnittet (m.a.o. bruk overloading).
- 2: Endre metoden i pakken som PK_FSWS kaller på.
- 3: Det gamle grensesnittet i PK_FSWS settes til å kalle på det nye grensesnittet.
- 4: Databasekoden deployes med disse endringene. Webservicen vil fortsatt gå mot gammelt grensesnitt, men dette delegerer videre til nytt. Ingenting feiler fordi alle metodene finnes.
- 5: Når databasekoden er rullet ut til alle baser kan man oppdatere webservicen til å kalle på det nye grensesnittet i PK_FSWS.
- 6: Webservicen deployes og vil nå virke mot nytt grensesnitt
- 7: Det gamle grensesnittet kan nå trygt fjernes fra PK_FSWS
Merk at denne omstendelige prosessen er ikke nødvendig dersom man bare endrer innholdet i en prosedyre, kun dersom man endrer på metodesignaturen (dvs. ved å legge til, fjerne eller endre parametere - evt. endre returtype).
Testing av integrasjoner
Testing av Webservice
Ved feilsøk kan det være nyttig å teste databasedelen for seg, noe som gjøres ved å kalle toppfunksjonen for den aktuelle webservicen direkte i SQL*Plus, Toad el.lign.
Når det gjelder testing av hele stacken (database + applikasjon) finnes det flere verktøy:
- SOAP: SOAP-UI
- REST: Advanced REST Client
- REST: Browser
- REST: Java-kode
- REST: Jenkins
Testing av REST med Javakode
I fsws-rest koden er det laget egne pakker med testkode, ligger under src/java/test. Disse kan kjøres i Eclipse. Åpne koden i Eclipse og høyreklikk på koden og velg "Run as" -> "JUnit Test".
Denne vil da kjøre koden og avgi rapport:
Dette kommer til å komme i Jenkins etterhvert som en natt-jobb.
Testing av overføring fra database
LMS
Databasedelen testes (for institusjonsnr nnnn) ved å kalle den aktuelle topprutinen (logget inn som Innnn_FS_WS):
- Fronter (alle parametere er valgfri):
- U/overføring: select FS.PK_FSWS_LMS.F_Fronter (LMSLopenr, Session_ID)
- M/overføring: exec FS.PK_FSWS_LMS.P_FronterEksport (LMSLopenr, Session_ID)
- Itslearning (alle parametere er valgfri):
- U/overføring / Full eksport : exec FS.PK_FSWS_LMS_ITSL.P_Full_Eksport (1, Session_ID, LMSLopenr)
- M/overføring / Full eksport : exec FS.PK_FSWS_LMS_ITSL.P_Full_Eksport (0, Session_ID, LMSLopenr)
- U/overføring / Inkr. eksport: exec FS.PK_FSWS_LMS_ITSL.P_Inkrementell_Eksport (1, Session_ID, LMSLopenr)
- M/overføring / Inkr. eksport: exec FS.PK_FSWS_LMS_ITSL.P_Inkrementell_Eksport (0, Session_ID, LMSLopenr)
- Parametere:
- LMSLopenr (default NULL begrenser ikke på LMSLopenr i kildetabeller)
- Session_ID (default: genereres av systemet)
Release/deployment
Applikasjon
Deployment i Utv (w3utv-jb01.uio.no)
- Domain/Overview
- Stopp fsws-1
- Deployments
- Velg fsws.war
- Replace
- Domain/Overview
- Start fsws.war
Deployment i Test (jboss-test.uio.no) eller Prod (fsws.usit.no)
WinSCP w3utv-jb01:
- Gå til ...\workspace\target (lokalt) og /tmp (remote)
- Overfør fsws-N.N.N.war
Be www-drift (RT) deploye den overførte fila.
Release
********************* Fyll ut *********************
Database
Deployment
Kompilering
Deployment av (endringer i) databasekode består av innlogging på det aktuelle FS-skjemaet og kompilering (kjøring av aktuell pakkekode fra fil):
- I Utv (FSUTV) og Demo (FS0nDMO / FSDEMO) kan dette gjøres fra klientsiden via SQL*Plus, Toad el.lign, da databaseutviklere som regel har direkte tilgang til disse miljøene
- I Prod (FS0nPRD / FSPROD) må dette normalt (dvs. hvis man ikke heter Geir eller Kari) gjøres via SQL*Plus på fs-patch01.
I utgangspunktet er det å foretrekke å kompilere ifm. nedetid, for ikke å påvirke evt. lange sesjoner som bruker den aktuelle koden. Dette gjelder en midlertidig og en permanent problemstilling:
- Den midlertidige er en databasebug som gjør at sesjonene risikerer å gå i spinn, og etterhvert få basen til å knele
- Den permanente er at sesjonene feiler ved de(t) første kallet (kallene) pga. forkastet tilstand i pakkevariable
Hvis kompilering gjøres mens basen er oppe
- Avklar hvilke apper som berøres av endringen
- Integrasjon (FSWS, FS-API)
- WebApp (StudentWeb, SøknadsWeb, FagpersonWeb...)
- FSWS, FS-API (flere?): Sperr tjenesten(e)
- Midlertidig: Synkroniser med oracle-drift: Overvåkning om X (+)
- WebApp: Logg på alle baser
- Vente X (+)
- FSWS: Flush
- Deploy i aktuelle baser
- Rekompiler evt. ugyldige objekter - automatisk?
- FSWS, WebApp: Flushe connections (+ cache?) for aktuelle applikasjoner
- Gjøres i Rundeck
- Først StudentWeb
- Deretter apper som brukes sjeldnere
- Hvis feilmeldinger ikke opphører:
- Prøv igjen
- Varsle www-drift (det er ikke alltid flush fungerer)
- Gjøres i Rundeck
- WebApp:
- Søk (++) etter feilmeldinger i translogger i alle baser:
- StudentWeb: SW3S_TRANSLOG
- SøknadsWeb: SOWS_TRANSLOG
- EVUWeb: EVUWEB_TRANSLOG
- Sjekk om feilmeldingene opphører etter flushing
- Hvis ikke: Flush igjen + Send hastemelding til www-drift (TEKST?)
- Søk (++) etter feilmeldinger i translogger i alle baser:
- FSWS: Flush igjen
- Åpne tjenesten(e) igjen
(+) Tiden det tar før tjenesten er stengt (om mulig):
- FSWS : 30 min
- FS-API: 2 timer
- WebApp: ?
(++) Spørringer mot translogger:
select procnavn, merknad_feil, Count(*)
from &translog -- En av loggtabellene over
where merknad_feil is not null
and sessiondate > sysdate - 1
group by procnavn, merknad_feil
/
select Max(sessiondate), sysdate
from &translog -- En av loggtabellene over
where merknad_feil is not null
and sessiondate > sysdate - 1
/
Release
For release av nye versjoner (vs. deployment av enkeltendringer) benyttes et Python-script:
scripts/build.py
Her kan man angi hvilken forrige release man ønsker å generere endringer siden (default er forrige release).
Troubleshooting
SoapUI
Det hender verktøyet cacher resultatet (t.o.m. ved parameterendringer!) - noe som kan vise seg ved uventet kort eksekveringstid og samme resultat som forrige request (der dette ikke er forventet). I så fall må man restarte klienten.
Feilmeldinger
ORA-64451: Conversion of special character to escaped character failed
- Årsak: Det forekommer kontrolltegn i dataene (typisk navn, adresse, merknadsfelt, URL...) - som regel pga. copy/paste fra Word el.lign.
- Quick fix: Kjør mistenkte delspørringer rad for rad (sortert) til feilen gjenskapes, og be institusjonen rette opp de aktuelle feltene
- Varig løsning: Få FS (database og/eller klient) til å forhindre slike verdier fra å bli lagres i fremtiden
ORA-28112: failed to execute policy function / ORA-28113: policy predicate has error
Betyr at en VPD-policy feiler. Disse er standard feilmeldinger som skjuler en bakenforliggende feil som i utgangspunktet ikke vises. Hvis man ikke finner årsaken ved kodeinspeksjon eller trace, må man be Drift om feilloggen fra databasen (udump-katalogen), der den bakenforliggende feilmeldingen vises.
ORA-12170: TNS: Det oppstod et tidsavbrudd for tilkoblingen
Kommer som regel av at man ikke slipper igjennom en brannmur.
No more data to read from socket
- Årsak: Dette er som regel noe på driftsnivå (applikasjonen er nede, feil i databasepeker, ...)
- Løsning: Restart av applikasjonen, rettelse av databasepeker, ...
Timeout
Det hender applikasjonsserveren eller webserveren avbryter et webservice-kall fordi det ikke avsluttes i løpet av den tidsgrensen som er angitt på serveren. Denne grensen kan variere (Drift ønsker typisk max 3 min, men vi har noen ganger bedt om det dobbelte eller mer i et begrenset tidsrom). Det første man bør gjøre er å avgjøre om problemet er på database- eller applikasjonsnivå, ved å kjøre kallet direkte i databasen. Hvis det går ut over timeout-grensen, blir det en tuning-jobb. Hvis ikke, er problemet på enten webserver- eller applikasjonsserver-nivå - med varierende løsningsforslag:
Webserver (Apache):
- Flush av cache
- Restart av server
Applikasjonsserver (JBoss):
- Restart av server