I am setting up java based graphQl App and find graphql-java-tools really convenient the problem though while itis pretty straight forward
With graphql-java to make field resolvers Async I couldn't Find a way to do it using graphql-java-tools
I tried
#Bean
public ExecutionStrategy executionStrategy() {
return new AsyncExecutionStrategy();
}
Here resolvers I use in order to test
#Component
public class VideoResolver implements GraphQLResolver<Video> {
public Episode getEpisode(Video video){
Episode result = new Episode();
result.setTitle("episodeTitle");
result.setUuid("EpisodeUuid");
result.setBrand("episodeBrand");
try {
Thread.sleep(2000L);
System.out.println(Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
return result;
}
public List<Images> getImages(Video video){
Images image = new Images();
image.setFileName("Image FileName1");
List<Images> imageList = new ArrayList<>();
imageList.add(image);
try {
Thread.sleep(2000L);
System.out.println(Thread.currentThread().getName());
} catch (InterruptedException e) {
System.out.println("Exxxxxxxxxx");
}
return imageList;
}
}
Was assuming this should run in about 2 seconds and print two different streams but no it takes 4
and print it is all in one same stream
Related
If while executing one rest method, at the same time came next request also so I need to prevent the second request and respond back "One person is already using". How to achieve this in spring boot? I tried the code below given. But it's not request rejected. Its added into a queue, after first request second one will execute.
#RestController
class TestController {
private static ReentrantLock lock = new ReentrantLock();
#GetMapping("tests")
public String get() {
System.err.println("----------------------------------------1 " + lock.isLocked());
if (!lock.tryLock()) {
System.err.println("--------------------------------------2 " + lock.isLocked());
return "failed";
}
try {
System.err.println("Application Locked");
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
lock.unlock();
}
return "success";
}
I've been trying to make a simple backend for user login.
It works fine if I don't use threads, but when I try to implement multi-threading it breaks for some reason.
For now, I'm just trying to do something as simple as retrieving all users' info from the User table in JSON format. The problem is that the Rest controller returns nothing to Postman even though dbActions.getAll() returns the correct List.
There's no error, no exception, nothing. I could really use some help. The parts of my code I'm trying to get to work are below.
Rest controller:
#Async
#RequestMapping(value="/view", method =RequestMethod.GET)
public List<User> viewAll() {
try {
List<User> list = new ArrayList<>();
list = dbActions.getAll();
return list;
}catch(Exception e) {
e.printStackTrace();
return null;
}
}
dbActions service:
public List<User> getAll() {
List<User> results = new ArrayList<>();
CompletableFuture<Void> future;
try {
future = CompletableFuture.runAsync(new Runnable() {
public void run() {
userRepo.findAll().forEach(results::add);
}
});
future.get();
return results;
} catch (Exception e) {
e.printStackTrace();
return results;
}
}
Try removing the #Async annotation from your viewAll() method
I am trying to read data from the database, and run process on each object concurrently.
My config as below,
#Bean
public Job job() {
return jobBuilderFactory.get("job").incrementer(new RunIdIncrementer()).listener(new Listener(videoDao))
.flow(step1()).end().build();
}
#Bean
public Step step1() {
return stepBuilderFactory.get("step1")
.<VideosDTO, VideosDTO>chunk(3)
.reader(databaseVideoItemReader(null))
.processor(new Processor())
.writer(new Writer(videoDao))
.build();
}
#Bean
#StepScope
ItemReader<VideosDTO> databaseVideoItemReader(#Value("#{jobParameters[userId]}") String userId) {
logger.info("Fetching videos for userId:"+userId);
JdbcCursorItemReader<VideosDTO> databaseReader = new JdbcCursorItemReader<>();
databaseReader.setDataSource(dataSource);
databaseReader.setSql("SELECT * FROM voc.t_videos where user_id="+userId+"AND job_success_ind='N'");
databaseReader.setRowMapper(new BeanPropertyRowMapper<>(VideosDTO.class));
// databaseReader.open(new ExecutionContext());
ExecutionContext executionContext= new ExecutionContext();
executionContext.size();
databaseReader.open(executionContext);
return databaseReader;
}
My item process is as below,
#Override
public VideosDTO process(VideosDTO videosDTO) throws Exception {
log.info("processing........" + videosDTO.getVideoUrl());
try {
Process p = Runtime.getRuntime()
.exec("C:\\Program Files\\Git\\bin\\bash.exe " + "D:\\DRM\\script.sh " + videosDTO.getVideoUrl());
// .exec("D:\\PortableGit\\bin\\bash.exe
// D:\\Vocabimate_Files\\script.sh "+videosDTO.getVideoUrl());
// Thread.sleep(1000);
Thread.sleep(1000);
p.destroy();
try {
p.waitFor();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try (InputStream is = p.getErrorStream()) {
int in = -1;
while ((in = is.read()) != -1) {
System.out.print((char) in);
}
}
try (InputStream is = p.getInputStream()) {
int in = -1;
while ((in = is.read()) != -1) {
System.out.print((char) in);
}
}
} catch (IOException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
return videosDTO;
}
writer is as below:
#Override
public void write(List<? extends VideosDTO>videosList) throws Exception {
for(VideosDTO vid:videosList){
log.info("writting...."+vid.getVideoUrl());
}
}
Suppose if there are 3 Objects fetched from DB this code first
complete process on first object,than second and than third than
starts writing.I want to Run process on the three object concurrently
at same time,than perform writing operation.
Is there any way to do this?
Using a multi-threaded step like suggested by #dimitrisli is the way to go. In addition to that, another way is to use the AsyncItemProcessor (in combination with an AsyncItemWriter).
A similar use case (calling a rest endpoint asynchronously from the processor) can be found here: https://stackoverflow.com/a/52309260/5019386 where I gave some more details.
Hope this helps.
Without getting into the details of your custom Reader/Processor/Writer, I think what you're looking for is a multi-threaded Step.
As also described in the above linked documentation in order to make your step multi-threaded (meaning reading/processing/writing each chunk in a separate thread) you first need to register a SimpleAsyncTaskExecutor:
#Bean
public TaskExecutor taskExecutor(){
return new SimpleAsyncTaskExecutor("myAsyncTaskExecutor");
}
and then register this task executor in your Step's builder:
#Bean
public Step step1() {
return stepBuilderFactory.get("step1")
.<VideosDTO, VideosDTO>chunk(3)
.reader(databaseVideoItemReader(null))
.processor(new Processor())
.writer(new Writer(videoDao))
//making the Step multi-threaded
.taskExecutor(taskExecutor())
.build();
}
I am having some problems with applying to reduce operation on Stream<Flux<T>>, I would like to reduce it to Flux<T>. Each AdProvider provides offers as Flux, I would like to use the stream to get all offers from each one of them and concatenate them to one pipeline. How could I possibly do that with reduce?
Set<AdProvider> adProviders;
#Override
#LogBefore
public void gather()
{
adProviders
.parallelStream()
.map(this::gatherOffers)
.reduce(?)
.subscribe();
}
private Flux<Ad> gatherOffers(AdProvider adProvider)
{
try
{
return adProvider.offers();
}
catch(Exception e)
{
log.warn(EXCEPTION_WHILE_PROCESSING_OFFERS, adProvider.getClass().getSimpleName(), e);
return Flux.empty();
}
}
Flatten Stream<Flux> using Flux#fromStream() + Flux#flatMap()
In order to solve the problem, you may combine Flux#fromStream() (which convert Stream<Flux> to Flux<Flux>) and Flux#flatMap() (which flatten inner fluxes to flat Flux) as in the following example:
Set<AdProvider> adProviders;
#Override
public void gather()
{
Flux.fromStream(adProviders.stream())
.parallel() // replace .parallelStream with separate parallel + runOn
.runOn(Schedulers.parallel())
.flatMap(this::gatherOffers)
.subscribe();
}
private Flux<Ad> gatherOffers(AdProvider adProvider)
{
try
{
return adProvider.offers();
}
catch(Exception e)
{
log.warn(EXCEPTION_WHILE_PROCESSING_OFFERS, adProvider.getClass().getSimpleName(), e);
return Flux.empty();
}
}
As it might be noticed, I replaced parallelStream with plain .stream and parallel + runOn which do almost the same.
Alternatively, you may avoid using stream at all and simply rely on Flux.fromIterble + the same Flux#flatMap:
Set<AdProvider> adProviders;
#Override
public void gather()
{
Flux.fromIterable(adProviders)
.parallel() // replace .parallelStream with separate parallel + runOn
.runOn(Schedulers.parallel())
.flatMap(this::gatherOffers)
.subscribe();
}
private Flux<Ad> gatherOffers(AdProvider adProvider)
{
try
{
return adProvider.offers();
}
catch(Exception e)
{
log.warn(EXCEPTION_WHILE_PROCESSING_OFFERS, adProvider.getClass().getSimpleName(), e);
return Flux.empty();
}
}
So I've been working on an extremely simple website over the past 2 days, but I figured it would be neat to somehow link the website with a Discord bot. For the Discord bot part, I've been using the JDA library.
The issue I'm running in to is that I seem to be unable to use the save method. However, the findById and findAll seem to work perfectly fine. The way I have my code setup can be found below.
#Controller
public class IndexController extends ListenerAdapter {
private static boolean botStarted = false;
#Autowired
private NewsPostRepository newsPostRepository;
#GetMapping("/")
public String getIndex(ModelMap map) {
// TODO: add news post images.
NewsPost savedNewsPost = newsPostRepository.save(new NewsPost("Controller", "Posted through controller",
new byte[]{}, new Date(), true));
System.out.println(savedNewsPost);
return "index";
}
#GetMapping("/start")
public String startBot() {
if (!botStarted) {
try {
JDA jda = new JDABuilder(AccountType.BOT)
.setToken("my-token")
.addEventListener(this)
.buildBlocking(); // Blocking vs async
} catch (LoginException e) {
e.printStackTrace();
} catch (RateLimitedException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
botStarted = true;
}
}
return "redirect:/";
}
#Override
public void onMessageReceived(MessageReceivedEvent messageReceivedEvent) {
User author = messageReceivedEvent.getAuthor();
MessageChannel channel = messageReceivedEvent.getChannel();
Message message = messageReceivedEvent.getMessage();
if (!author.isBot()) {
if (message.getContent().startsWith("!news")) {
NewsPost savedNewsPost = newsPostRepository.save(new NewsPost("Discord", "Posted through Discord",
new byte[]{}, new Date(), true));
System.out.println(savedNewsPost);
}
}
}
}
The repository:
public interface NewsPostRepository extends CrudRepository<NewsPost, String> {
}
The weird thing is, that when I go to the index page, the NewsPost saves perfectly fine, and is visible in the database.
When I try to use the Discord bot to add a NewsPost, it returns an object in the same way it would in the method for the index, with an ID that is not null and should be usable to find it in the database, however, this entry is nowhere to be found. No exception appears either. Keep in mind that both of these save() calls are identical.
I've tried to use a service and adding #Transactional but so far nothing has worked.